diff --git a/composer.go b/composer.go index 16e7694..b4a4522 100644 --- a/composer.go +++ b/composer.go @@ -378,7 +378,7 @@ func (c *Composer) processMouseClick(ev term.Event) { c.RefreshScreen(true) } else if hit == HitButtonClose { if len(c.views) > 1 { - event := Event{Type: EventClose} + event := Event{Type: EventClose, X: 1} c.sendEventToActiveView(event) c.DestroyView(view) diff --git a/consts.go b/consts.go index 5270936..ce70b11 100644 --- a/consts.go +++ b/consts.go @@ -21,13 +21,14 @@ type Box struct { // Predefined types type ( - BorderStyle int - ViewButton int - HitResult int - Align int - EventType int - Direction int - PackType int + BorderStyle int + ViewButton int + HitResult int + Align int + EventType int + Direction int + PackType int + SelectDialogType uint ) // Internal event structure. Used by Windows and controls to communicate with Composer @@ -227,3 +228,8 @@ var ( ButtonsYesNo = []string{"Yes", "No"} ButtonsYesNoCancel = []string{"Yes", "No", "Cancel"} ) + +const ( + SelectDialogList = iota + SelectDialogRadio +) diff --git a/dialog.go b/dialog.go index f6f3e46..26dcd48 100644 --- a/dialog.go +++ b/dialog.go @@ -11,6 +11,17 @@ type ConfirmationDialog struct { onClose func() } +type SelectDialog struct { + view View + parent *Composer + result int + value int + rg *RadioGroup + list *ListBox + typ SelectDialogType + onClose func() +} + func NewConfirmationDialog(c *Composer, title, question string, buttons []string, defaultButton int) *ConfirmationDialog { dlg := new(ConfirmationDialog) @@ -84,7 +95,9 @@ func NewConfirmationDialog(c *Composer, title, question string, buttons []string dlg.view.OnClose(func(ev Event) { if dlg.result == DialogAlive { dlg.result = DialogClosed - c.DestroyView(dlg.view) + if ev.X != 1 { + c.DestroyView(dlg.view) + } if dlg.onClose != nil { go dlg.onClose() } @@ -101,3 +114,100 @@ func (d *ConfirmationDialog) OnClose(fn func()) { func (d *ConfirmationDialog) Result() int { return d.result } + +// ------------------------ Selection Dialog --------------------- + +func NewSelectDialog(c *Composer, title string, items []string, selectedItem int, typ SelectDialogType) *SelectDialog { + dlg := new(SelectDialog) + + if len(items) == 0 { + panic("Item list must contain at least 1 item") + } + + cw, ch := term.Size() + + dlg.parent = c + dlg.typ = typ + dlg.view = c.CreateView(cw/2-12, ch/2-8, 20, 10, title) + dlg.view.SetModal(true) + dlg.view.SetPack(Vertical) + + if typ == SelectDialogList { + fList := NewFrame(dlg.view, dlg.view, 1, 1, BorderNone, 1) + fList.SetPaddings(1, 1, 0, 0) + dlg.list = NewListBox(dlg.view, fList, 15, 5, 1) + for _, item := range items { + dlg.list.AddItem(item) + } + if selectedItem >= 0 && selectedItem < len(items) { + dlg.list.SelectItem(selectedItem) + } + } else { + fRadio := NewFrame(dlg.view, dlg.view, 1, 1, BorderNone, DoNotScale) + fRadio.SetPaddings(1, 1, 0, 0) + fRadio.SetPack(Vertical) + dlg.rg = NewRadioGroup() + for _, item := range items { + r := NewRadio(dlg.view, fRadio, AutoSize, item, DoNotScale) + dlg.rg.AddItem(r) + } + if selectedItem >= 0 && selectedItem < len(items) { + dlg.rg.SetSelected(selectedItem) + } + } + + frm1 := NewFrame(dlg.view, dlg.view, 16, 4, BorderNone, DoNotScale) + NewFrame(dlg.view, frm1, 1, 1, BorderNone, 1) + btn1 := NewButton(dlg.view, frm1, AutoSize, AutoSize, "OK", DoNotScale) + btn1.OnClick(func(ev Event) { + dlg.result = DialogButton1 + if dlg.typ == SelectDialogList { + dlg.value = dlg.list.SelectedItem() + } else { + dlg.value = dlg.rg.Selected() + } + c.DestroyView(dlg.view) + if dlg.onClose != nil { + go dlg.onClose() + } + }) + + NewFrame(dlg.view, frm1, 1, 1, BorderNone, 1) + btn2 := NewButton(dlg.view, frm1, AutoSize, AutoSize, "Cancel", DoNotScale) + btn2.OnClick(func(ev Event) { + dlg.result = DialogButton2 + dlg.value = -1 + c.DestroyView(dlg.view) + if dlg.onClose != nil { + go dlg.onClose() + } + }) + dlg.view.ActivateControl(btn2) + NewFrame(dlg.view, frm1, 1, 1, BorderNone, 1) + + dlg.view.OnClose(func(ev Event) { + if dlg.result == DialogAlive { + dlg.result = DialogClosed + if ev.X != 1 { + c.DestroyView(dlg.view) + } + if dlg.onClose != nil { + go dlg.onClose() + } + } + }) + + return dlg +} + +func (d *SelectDialog) OnClose(fn func()) { + d.onClose = fn +} + +func (d *SelectDialog) Result() int { + return d.result +} + +func (d *SelectDialog) Value() int { + return d.value +} diff --git a/listbox.go b/listbox.go index 5f37ba3..33b004f 100644 --- a/listbox.go +++ b/listbox.go @@ -254,7 +254,7 @@ func (l *ListBox) processMouseClick(ev Event) bool { l.SelectItem(l.topLine + dy) if l.onSelectItem != nil { - ev := Event{Y: l.topLine + dy, Msg: l.GetSelectedItem()} + ev := Event{Y: l.topLine + dy, Msg: l.SelectedItemText()} go l.onSelectItem(ev) } @@ -300,7 +300,7 @@ func (l *ListBox) ProcessEvent(event Event) bool { return true case term.KeyCtrlM: if l.currSelection != -1 && l.onSelectItem != nil { - ev := Event{Y: l.currSelection, Msg: l.GetSelectedItem()} + ev := Event{Y: l.currSelection, Msg: l.SelectedItemText()} go l.onSelectItem(ev) } default: @@ -352,9 +352,14 @@ func (l *ListBox) FindItem(text string, caseSensitive bool) int { return -1 } +// Returns currently selected item id +func (l *ListBox) SelectedItem() int { + return l.currSelection +} + // Returns text of currently selected item or empty sting if nothing is // selected or ListBox is empty -func (l *ListBox) GetSelectedItem() string { +func (l *ListBox) SelectedItemText() string { if l.currSelection == -1 { return "" } diff --git a/window.go b/window.go index 9eae1df..0dbe4bb 100644 --- a/window.go +++ b/window.go @@ -322,7 +322,7 @@ func (w *Window) ProcessEvent(ev Event) bool { } case EventClose: if w.onClose != nil { - w.onClose(Event{Type: EventClose}) + w.onClose(Event{Type: EventClose, X: ev.X}) } // case EventResize: // d.hideAllExtraControls()