2015-10-21 17:04:57 -07:00
|
|
|
package clui
|
|
|
|
|
|
|
|
import (
|
|
|
|
term "github.com/nsf/termbox-go"
|
|
|
|
)
|
|
|
|
|
2015-10-28 14:17:49 -07:00
|
|
|
// ConfirmationDialog is a simple dialog to get a user
|
|
|
|
// choice or confirmation. The dialog can contain upto
|
|
|
|
// three button with custom titles. There are a few
|
|
|
|
// predefined button sets: see Buttons* constants.
|
|
|
|
// The dialog is modal, so a user cannot interact other
|
|
|
|
// Views until the user closes the dialog
|
2015-10-22 13:37:38 -07:00
|
|
|
type ConfirmationDialog struct {
|
2018-01-24 19:23:00 +11:00
|
|
|
View *Window
|
2015-10-21 17:04:57 -07:00
|
|
|
result int
|
|
|
|
onClose func()
|
|
|
|
}
|
|
|
|
|
2015-10-28 14:17:49 -07:00
|
|
|
// SelectDialog allows to user to select an item from
|
|
|
|
// the list. Items can be displayed in ListBox or in
|
|
|
|
// RadioGroup.
|
|
|
|
// The dialog is modal, so a user cannot interact other
|
|
|
|
// Views until the user closes the dialog
|
2015-10-22 14:44:19 -07:00
|
|
|
type SelectDialog struct {
|
2018-01-24 19:23:00 +11:00
|
|
|
View *Window
|
2015-10-22 14:44:19 -07:00
|
|
|
result int
|
|
|
|
value int
|
|
|
|
rg *RadioGroup
|
|
|
|
list *ListBox
|
|
|
|
typ SelectDialogType
|
|
|
|
onClose func()
|
|
|
|
}
|
|
|
|
|
2018-01-24 19:21:05 +11:00
|
|
|
// CreateAlertDialog creates a new alert dialog.
|
|
|
|
// title is a dialog title
|
|
|
|
// message is a text inside dialog for user to be notified of a fact
|
|
|
|
// button is a title for button inside dialog.
|
|
|
|
func CreateAlertDialog(title, message string, button string) *ConfirmationDialog {
|
|
|
|
return CreateConfirmationDialog(title, message, []string{button}, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateConfirmationDialog creates new confirmation dialog.
|
2015-10-28 14:17:49 -07:00
|
|
|
// c is a composer that manages the dialog
|
|
|
|
// title is a dialog title
|
|
|
|
// question is a text inside dialog for user to explain what happens
|
|
|
|
// buttons is a titles for button inside dialog. If the list is empty,
|
|
|
|
// the dialog will have only one button 'OK'. If the list has more
|
|
|
|
// than 3 button then only first three items will be used in the dialog
|
|
|
|
// defaultButton is the number of button that is active right after
|
|
|
|
// dialog is created. If the number is greater than the number of
|
|
|
|
// buttons, no button is active
|
2016-10-13 14:16:05 -07:00
|
|
|
func CreateConfirmationDialog(title, question string, buttons []string, defaultButton int) *ConfirmationDialog {
|
2015-10-22 13:37:38 -07:00
|
|
|
dlg := new(ConfirmationDialog)
|
|
|
|
|
|
|
|
if len(buttons) == 0 {
|
|
|
|
buttons = []string{"OK"}
|
|
|
|
}
|
2015-10-21 17:04:57 -07:00
|
|
|
|
|
|
|
cw, ch := term.Size()
|
|
|
|
|
2018-01-24 19:23:00 +11:00
|
|
|
dlg.View = AddWindow(cw/2-12, ch/2-8, 30, 3, title)
|
2018-01-25 21:49:43 -08:00
|
|
|
WindowManager().BeginUpdate()
|
|
|
|
defer WindowManager().EndUpdate()
|
2018-01-24 19:23:00 +11:00
|
|
|
dlg.View.SetConstraints(30, 3)
|
|
|
|
dlg.View.SetModal(true)
|
|
|
|
dlg.View.SetPack(Vertical)
|
|
|
|
CreateFrame(dlg.View, 1, 1, BorderNone, Fixed)
|
2015-10-21 17:04:57 -07:00
|
|
|
|
2018-01-24 19:23:00 +11:00
|
|
|
fbtn := CreateFrame(dlg.View, 1, 1, BorderNone, 1)
|
2016-10-13 14:16:05 -07:00
|
|
|
CreateFrame(fbtn, 1, 1, BorderNone, Fixed)
|
|
|
|
lb := CreateLabel(fbtn, 10, 3, question, 1)
|
2015-10-21 17:04:57 -07:00
|
|
|
lb.SetMultiline(true)
|
2016-10-13 14:16:05 -07:00
|
|
|
CreateFrame(fbtn, 1, 1, BorderNone, Fixed)
|
2015-10-21 17:04:57 -07:00
|
|
|
|
2018-01-24 19:23:00 +11:00
|
|
|
CreateFrame(dlg.View, 1, 1, BorderNone, Fixed)
|
|
|
|
frm1 := CreateFrame(dlg.View, 16, 4, BorderNone, Fixed)
|
2016-10-13 14:16:05 -07:00
|
|
|
CreateFrame(frm1, 1, 1, BorderNone, 1)
|
2015-10-22 13:37:38 -07:00
|
|
|
|
|
|
|
bText := buttons[0]
|
2016-10-13 14:16:05 -07:00
|
|
|
btn1 := CreateButton(frm1, AutoSize, AutoSize, bText, Fixed)
|
2015-10-22 13:37:38 -07:00
|
|
|
btn1.OnClick(func(ev Event) {
|
|
|
|
dlg.result = DialogButton1
|
2018-01-26 18:15:43 +11:00
|
|
|
|
2018-01-24 19:23:00 +11:00
|
|
|
WindowManager().DestroyWindow(dlg.View)
|
2018-01-25 21:49:43 -08:00
|
|
|
WindowManager().BeginUpdate()
|
|
|
|
closeFunc := dlg.onClose
|
|
|
|
WindowManager().EndUpdate()
|
|
|
|
if closeFunc != nil {
|
2018-01-27 14:21:28 -08:00
|
|
|
closeFunc()
|
2015-10-22 13:37:38 -07:00
|
|
|
}
|
|
|
|
})
|
|
|
|
var btn2, btn3 *Button
|
|
|
|
|
|
|
|
if len(buttons) > 1 {
|
2016-10-13 14:16:05 -07:00
|
|
|
CreateFrame(frm1, 1, 1, BorderNone, 1)
|
|
|
|
btn2 = CreateButton(frm1, AutoSize, AutoSize, buttons[1], Fixed)
|
2015-10-22 13:37:38 -07:00
|
|
|
btn2.OnClick(func(ev Event) {
|
|
|
|
dlg.result = DialogButton2
|
2018-01-24 19:23:00 +11:00
|
|
|
WindowManager().DestroyWindow(dlg.View)
|
2015-10-22 13:37:38 -07:00
|
|
|
if dlg.onClose != nil {
|
2018-01-27 14:21:28 -08:00
|
|
|
dlg.onClose()
|
2015-10-22 13:37:38 -07:00
|
|
|
}
|
|
|
|
})
|
2015-10-21 17:04:57 -07:00
|
|
|
}
|
2015-10-22 13:37:38 -07:00
|
|
|
if len(buttons) > 2 {
|
2016-10-13 14:16:05 -07:00
|
|
|
CreateFrame(frm1, 1, 1, BorderNone, 1)
|
|
|
|
btn3 = CreateButton(frm1, AutoSize, AutoSize, buttons[2], Fixed)
|
2015-10-22 13:37:38 -07:00
|
|
|
btn3.OnClick(func(ev Event) {
|
|
|
|
dlg.result = DialogButton3
|
2018-01-24 19:23:00 +11:00
|
|
|
WindowManager().DestroyWindow(dlg.View)
|
2015-10-22 13:37:38 -07:00
|
|
|
if dlg.onClose != nil {
|
2018-01-27 14:21:28 -08:00
|
|
|
dlg.onClose()
|
2015-10-22 13:37:38 -07:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-10-13 14:16:05 -07:00
|
|
|
CreateFrame(frm1, 1, 1, BorderNone, 1)
|
2015-10-21 17:04:57 -07:00
|
|
|
|
2017-09-07 15:32:25 -07:00
|
|
|
if defaultButton == DialogButton2 && len(buttons) > 1 {
|
2018-01-24 19:23:00 +11:00
|
|
|
ActivateControl(dlg.View, btn2)
|
2017-09-07 15:32:25 -07:00
|
|
|
} else if defaultButton == DialogButton3 && len(buttons) > 2 {
|
2018-01-24 19:23:00 +11:00
|
|
|
ActivateControl(dlg.View, btn3)
|
2018-01-25 21:49:43 -08:00
|
|
|
} else {
|
2018-01-24 19:23:00 +11:00
|
|
|
ActivateControl(dlg.View, btn1)
|
2018-01-25 21:49:43 -08:00
|
|
|
}
|
2017-09-07 15:32:25 -07:00
|
|
|
|
2018-01-24 19:23:00 +11:00
|
|
|
dlg.View.OnClose(func(ev Event) bool {
|
2015-10-21 17:04:57 -07:00
|
|
|
if dlg.result == DialogAlive {
|
|
|
|
dlg.result = DialogClosed
|
2015-10-22 14:44:19 -07:00
|
|
|
if ev.X != 1 {
|
2018-01-24 19:23:00 +11:00
|
|
|
WindowManager().DestroyWindow(dlg.View)
|
2015-10-22 14:44:19 -07:00
|
|
|
}
|
2015-10-21 17:04:57 -07:00
|
|
|
if dlg.onClose != nil {
|
2018-01-27 14:21:28 -08:00
|
|
|
dlg.onClose()
|
2015-10-21 17:04:57 -07:00
|
|
|
}
|
|
|
|
}
|
2017-07-04 18:04:58 -07:00
|
|
|
return true
|
2015-10-21 17:04:57 -07:00
|
|
|
})
|
|
|
|
|
|
|
|
return dlg
|
|
|
|
}
|
|
|
|
|
2015-10-28 14:17:49 -07:00
|
|
|
// OnClose sets the callback that is called when the
|
|
|
|
// dialog is closed
|
2015-10-22 13:37:38 -07:00
|
|
|
func (d *ConfirmationDialog) OnClose(fn func()) {
|
2018-01-25 21:49:43 -08:00
|
|
|
WindowManager().BeginUpdate()
|
|
|
|
defer WindowManager().EndUpdate()
|
2015-10-21 17:04:57 -07:00
|
|
|
d.onClose = fn
|
|
|
|
}
|
|
|
|
|
2015-10-28 14:17:49 -07:00
|
|
|
// Result returns what button closed the dialog.
|
|
|
|
// See DialogButton constants. It can equal DialogAlive
|
|
|
|
// that means that the dialog is still visible and a
|
|
|
|
// user still does not click any button
|
2015-10-22 13:37:38 -07:00
|
|
|
func (d *ConfirmationDialog) Result() int {
|
2015-10-21 17:04:57 -07:00
|
|
|
return d.result
|
|
|
|
}
|
2015-10-22 14:44:19 -07:00
|
|
|
|
|
|
|
// ------------------------ Selection Dialog ---------------------
|
|
|
|
|
2015-10-28 14:17:49 -07:00
|
|
|
// NewSelectDialog creates new dialog to select an item from list.
|
|
|
|
// c is a composer that manages the dialog
|
|
|
|
// title is a dialog title
|
|
|
|
// items is a list of items to select from
|
|
|
|
// selectedItem is the index of the item that is selected after
|
|
|
|
// the dialog is created
|
|
|
|
// typ is a selection type: ListBox or RadioGroup
|
2015-12-08 16:25:31 -08:00
|
|
|
// Returns nil in case of creation process fails, e.g, if item list is empty
|
2016-10-13 14:16:05 -07:00
|
|
|
func CreateSelectDialog(title string, items []string, selectedItem int, typ SelectDialogType) *SelectDialog {
|
2015-10-22 14:44:19 -07:00
|
|
|
dlg := new(SelectDialog)
|
|
|
|
|
|
|
|
if len(items) == 0 {
|
2015-12-08 16:25:31 -08:00
|
|
|
// Item list must contain at least 1 item
|
|
|
|
return nil
|
2015-10-22 14:44:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
cw, ch := term.Size()
|
|
|
|
|
|
|
|
dlg.typ = typ
|
2018-01-24 19:23:00 +11:00
|
|
|
dlg.View = AddWindow(cw/2-12, ch/2-8, 20, 10, title)
|
2018-01-25 21:49:43 -08:00
|
|
|
WindowManager().BeginUpdate()
|
|
|
|
defer WindowManager().EndUpdate()
|
2018-01-24 19:23:00 +11:00
|
|
|
dlg.View.SetModal(true)
|
|
|
|
dlg.View.SetPack(Vertical)
|
2015-10-22 14:44:19 -07:00
|
|
|
|
|
|
|
if typ == SelectDialogList {
|
2018-01-24 19:23:00 +11:00
|
|
|
fList := CreateFrame(dlg.View, 1, 1, BorderNone, 1)
|
2016-10-13 14:16:05 -07:00
|
|
|
fList.SetPaddings(1, 1)
|
|
|
|
fList.SetGaps(0, 0)
|
|
|
|
dlg.list = CreateListBox(fList, 15, 5, 1)
|
2015-10-22 14:44:19 -07:00
|
|
|
for _, item := range items {
|
|
|
|
dlg.list.AddItem(item)
|
|
|
|
}
|
|
|
|
if selectedItem >= 0 && selectedItem < len(items) {
|
|
|
|
dlg.list.SelectItem(selectedItem)
|
|
|
|
}
|
|
|
|
} else {
|
2018-01-24 19:23:00 +11:00
|
|
|
fRadio := CreateFrame(dlg.View, 1, 1, BorderNone, Fixed)
|
2016-10-13 14:16:05 -07:00
|
|
|
fRadio.SetPaddings(1, 1)
|
|
|
|
fRadio.SetGaps(0, 0)
|
2015-10-22 14:44:19 -07:00
|
|
|
fRadio.SetPack(Vertical)
|
2016-10-13 14:16:05 -07:00
|
|
|
dlg.rg = CreateRadioGroup()
|
2015-10-22 14:44:19 -07:00
|
|
|
for _, item := range items {
|
2016-10-13 14:16:05 -07:00
|
|
|
r := CreateRadio(fRadio, AutoSize, item, Fixed)
|
2015-10-22 14:44:19 -07:00
|
|
|
dlg.rg.AddItem(r)
|
|
|
|
}
|
|
|
|
if selectedItem >= 0 && selectedItem < len(items) {
|
|
|
|
dlg.rg.SetSelected(selectedItem)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-24 19:23:00 +11:00
|
|
|
frm1 := CreateFrame(dlg.View, 16, 4, BorderNone, Fixed)
|
2016-10-13 14:16:05 -07:00
|
|
|
CreateFrame(frm1, 1, 1, BorderNone, 1)
|
|
|
|
btn1 := CreateButton(frm1, AutoSize, AutoSize, "OK", Fixed)
|
2015-10-22 14:44:19 -07:00
|
|
|
btn1.OnClick(func(ev Event) {
|
|
|
|
dlg.result = DialogButton1
|
|
|
|
if dlg.typ == SelectDialogList {
|
|
|
|
dlg.value = dlg.list.SelectedItem()
|
|
|
|
} else {
|
|
|
|
dlg.value = dlg.rg.Selected()
|
|
|
|
}
|
2018-01-24 19:23:00 +11:00
|
|
|
WindowManager().DestroyWindow(dlg.View)
|
2015-10-22 14:44:19 -07:00
|
|
|
if dlg.onClose != nil {
|
2018-01-27 14:21:28 -08:00
|
|
|
dlg.onClose()
|
2015-10-22 14:44:19 -07:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2016-10-13 14:16:05 -07:00
|
|
|
CreateFrame(frm1, 1, 1, BorderNone, 1)
|
|
|
|
btn2 := CreateButton(frm1, AutoSize, AutoSize, "Cancel", Fixed)
|
2015-10-22 14:44:19 -07:00
|
|
|
btn2.OnClick(func(ev Event) {
|
|
|
|
dlg.result = DialogButton2
|
|
|
|
dlg.value = -1
|
2018-01-24 19:23:00 +11:00
|
|
|
WindowManager().DestroyWindow(dlg.View)
|
2015-10-22 14:44:19 -07:00
|
|
|
if dlg.onClose != nil {
|
2018-01-27 14:21:28 -08:00
|
|
|
dlg.onClose()
|
2015-10-22 14:44:19 -07:00
|
|
|
}
|
|
|
|
})
|
2018-01-24 19:23:00 +11:00
|
|
|
ActivateControl(dlg.View, btn2)
|
2016-10-13 14:16:05 -07:00
|
|
|
CreateFrame(frm1, 1, 1, BorderNone, 1)
|
2015-10-22 14:44:19 -07:00
|
|
|
|
2018-01-24 19:23:00 +11:00
|
|
|
dlg.View.OnClose(func(ev Event) bool {
|
2015-10-22 14:44:19 -07:00
|
|
|
if dlg.result == DialogAlive {
|
|
|
|
dlg.result = DialogClosed
|
|
|
|
if ev.X != 1 {
|
2018-01-24 19:23:00 +11:00
|
|
|
WindowManager().DestroyWindow(dlg.View)
|
2015-10-22 14:44:19 -07:00
|
|
|
}
|
|
|
|
if dlg.onClose != nil {
|
2018-01-27 14:21:28 -08:00
|
|
|
dlg.onClose()
|
2015-10-22 14:44:19 -07:00
|
|
|
}
|
|
|
|
}
|
2017-07-04 18:04:58 -07:00
|
|
|
|
|
|
|
return true
|
2015-10-22 14:44:19 -07:00
|
|
|
})
|
|
|
|
|
|
|
|
return dlg
|
|
|
|
}
|
|
|
|
|
2015-10-28 14:17:49 -07:00
|
|
|
// OnClose sets the callback that is called when the
|
|
|
|
// dialog is closed
|
2015-10-22 14:44:19 -07:00
|
|
|
func (d *SelectDialog) OnClose(fn func()) {
|
2018-01-25 21:49:43 -08:00
|
|
|
WindowManager().BeginUpdate()
|
|
|
|
defer WindowManager().EndUpdate()
|
2015-10-22 14:44:19 -07:00
|
|
|
d.onClose = fn
|
|
|
|
}
|
|
|
|
|
2015-10-28 14:17:49 -07:00
|
|
|
// Result returns what button closed the dialog.
|
|
|
|
// See DialogButton constants. It can equal DialogAlive
|
|
|
|
// that means that the dialog is still visible and a
|
|
|
|
// user still does not click any button
|
2015-10-22 14:44:19 -07:00
|
|
|
func (d *SelectDialog) Result() int {
|
|
|
|
return d.result
|
|
|
|
}
|
|
|
|
|
2015-10-28 14:17:49 -07:00
|
|
|
// Value returns the number of the selected item or
|
|
|
|
// -1 if nothing is selected or the dialog is cancelled
|
2015-10-22 14:44:19 -07:00
|
|
|
func (d *SelectDialog) Value() int {
|
|
|
|
return d.value
|
|
|
|
}
|