2024-05-18 11:25:06 -06:00
|
|
|
package objects
|
|
|
|
|
|
|
|
import "image"
|
|
|
|
import "git.tebibyte.media/tomo/tomo"
|
|
|
|
import "git.tebibyte.media/tomo/tomo/event"
|
|
|
|
import "git.tebibyte.media/tomo/tomo/theme"
|
|
|
|
import "git.tebibyte.media/tomo/objects/layouts"
|
|
|
|
|
|
|
|
// DialogKind defines the semantic role of a dialog window.
|
|
|
|
type DialogKind int; const (
|
|
|
|
DialogInformation DialogKind = iota
|
|
|
|
DialogQuestion
|
|
|
|
DialogWarning
|
|
|
|
DialogError
|
|
|
|
)
|
|
|
|
|
|
|
|
// Dialog is a modal dialog window.
|
|
|
|
type Dialog struct {
|
|
|
|
tomo.Window
|
|
|
|
controlRow tomo.ContainerBox
|
|
|
|
}
|
|
|
|
|
|
|
|
type clickable interface {
|
|
|
|
OnClick (func ()) event.Cookie
|
|
|
|
}
|
|
|
|
|
2024-05-18 12:16:57 -06:00
|
|
|
// NewDialog creates a new dialog window given a dialog kind.
|
|
|
|
func NewDialog (kind DialogKind, parent tomo.Window, title, message string, options ...tomo.Object) (*Dialog, error) {
|
2024-05-18 11:25:06 -06:00
|
|
|
if title == "" {
|
|
|
|
switch kind {
|
|
|
|
case DialogInformation: title = "Information"
|
|
|
|
case DialogQuestion: title = "Question"
|
|
|
|
case DialogWarning: title = "Warning"
|
|
|
|
case DialogError: title = "Error"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dialog := &Dialog { }
|
|
|
|
if parent == nil {
|
|
|
|
window, err := tomo.NewWindow(image.Rectangle { })
|
|
|
|
if err != nil { return nil, err }
|
|
|
|
dialog.Window = window
|
|
|
|
} else {
|
|
|
|
window, err := parent.NewModal(image.Rectangle { })
|
|
|
|
if err != nil { return nil, err }
|
|
|
|
dialog.Window = window
|
|
|
|
}
|
|
|
|
|
|
|
|
var iconId theme.Icon
|
|
|
|
switch kind {
|
|
|
|
case DialogInformation: iconId = theme.IconStatusInformation
|
|
|
|
case DialogQuestion: iconId = theme.IconStatusQuestion
|
|
|
|
case DialogWarning: iconId = theme.IconStatusWarning
|
|
|
|
case DialogError: iconId = theme.IconStatusError
|
|
|
|
}
|
|
|
|
dialog.SetTitle(title)
|
|
|
|
icon := NewIcon(iconId, theme.IconSizeLarge)
|
|
|
|
messageText := NewLabel(message)
|
|
|
|
messageText.SetAlign(tomo.AlignStart, tomo.AlignMiddle)
|
|
|
|
|
|
|
|
for _, option := range options {
|
|
|
|
if option, ok := option.(clickable); ok {
|
|
|
|
option.OnClick(dialog.Close)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dialog.controlRow = NewInnerContainer(layouts.ContractHorizontal, options...)
|
|
|
|
dialog.controlRow.SetAlign(tomo.AlignEnd, tomo.AlignEnd)
|
|
|
|
|
|
|
|
dialog.SetRoot(NewOuterContainer (
|
|
|
|
layouts.NewGrid([]bool { true }, []bool { true, false }),
|
|
|
|
NewInnerContainer(layouts.ContractHorizontal, icon, messageText),
|
|
|
|
dialog.controlRow))
|
|
|
|
return dialog, nil
|
|
|
|
}
|
|
|
|
|
2024-05-18 12:16:57 -06:00
|
|
|
// NewDialogOk creates a new dialog window with an OK option.
|
|
|
|
func NewDialogOk (kind DialogKind, parent tomo.Window, title, message string, onOk func ()) (*Dialog, error) {
|
2024-05-18 11:25:06 -06:00
|
|
|
okButton := NewButton("OK")
|
|
|
|
okButton.SetIcon(theme.IconStatusOkay)
|
|
|
|
okButton.OnClick(func () {
|
|
|
|
if onOk != nil { onOk() }
|
|
|
|
})
|
|
|
|
okButton.SetFocused(true)
|
|
|
|
|
2024-05-18 12:16:57 -06:00
|
|
|
return NewDialog(kind, parent, title, message, okButton)
|
2024-05-18 11:25:06 -06:00
|
|
|
}
|
|
|
|
|
2024-05-18 12:16:57 -06:00
|
|
|
// NewDialogOkCancel creates a new dialog window with OK and Cancel options.
|
|
|
|
func NewDialogOkCancel (kind DialogKind, parent tomo.Window, title, message string, onOk func ()) (*Dialog, error) {
|
2024-05-18 11:25:06 -06:00
|
|
|
cancelButton := NewButton("Cancel")
|
|
|
|
cancelButton.SetIcon(theme.IconStatusCancel)
|
|
|
|
|
|
|
|
okButton := NewButton("OK")
|
|
|
|
okButton.SetIcon(theme.IconStatusOkay)
|
|
|
|
okButton.OnClick(func () {
|
|
|
|
if onOk != nil { onOk() }
|
|
|
|
})
|
|
|
|
okButton.SetFocused(true)
|
|
|
|
|
2024-05-18 12:16:57 -06:00
|
|
|
return NewDialog(kind, parent, title, message, cancelButton, okButton)
|
2024-05-18 11:25:06 -06:00
|
|
|
}
|