Standardized message boxes so they appear similarly on all platforms. This shafts Windows because primary/secondary text message boxes were only added in Windows Vista, but at least MSDN provides discourse.

This commit is contained in:
Pietro Gagliardi 2014-03-12 12:14:24 -04:00
parent 6eea59c30a
commit 2fb7056be4
6 changed files with 45 additions and 39 deletions

View File

@ -2,16 +2,19 @@
package ui
import (
"fmt"
// ...
)
// MsgBox displays an informational message box to the user with just an OK button.
func MsgBox(title string, textfmt string, args ...interface{}) {
msgBox(title, fmt.Sprintf(textfmt, args...))
// primaryText should be a short string describing the message, and will be displayed with additional emphasis on platforms that support it.
// secondaryText can be used to provide more information.
// On platforms that allow for the message box window to have a title, os.Args[0] is used.
func MsgBox(primaryText string, secondaryText string) {
msgBox(primaryText, secondaryText)
}
// MsgBoxError displays a message box to the user with just an OK button and an icon indicating an error.
func MsgBoxError(title string, textfmt string, args ...interface{}) {
msgBoxError(title, fmt.Sprintf(textfmt, args...))
// Otherwise, it behaves like MsgBox.
func MsgBoxError(primaryText string, secondaryText string) {
msgBoxError(primaryText, secondaryText)
}

View File

@ -26,14 +26,13 @@ var (
_runModal = sel_getUid("runModal")
)
func _msgBox(title string, text string, style uintptr, button0 string) {
func _msgBox(primarytext string, secondarytext string, style uintptr, button0 string) {
ret := make(chan struct{})
defer close(ret)
uitask <- func() {
box := objc_new(_NSAlert)
// TODO is this appropriate for title?
C.objc_msgSend_id(box, _setMessageText, toNSString(title))
C.objc_msgSend_id(box, _setInformativeText, toNSString(text))
C.objc_msgSend_id(box, _setMessageText, toNSString(primarytext))
C.objc_msgSend_id(box, _setInformativeText, toNSString(secondarytext))
objc_msgSend_uint(box, _setAlertStyle, style)
C.objc_msgSend_id(box, _addButtonWithTitle, toNSString(button0))
C.objc_msgSend_noargs(box, _runModal)
@ -42,11 +41,11 @@ func _msgBox(title string, text string, style uintptr, button0 string) {
<-ret
}
func msgBox(title string, text string) {
func msgBox(primarytext string, secondarytext string) {
// TODO _NSInformationalAlertStyle?
_msgBox(title, text, _NSWarningAlertStyle, "OK")
_msgBox(primarytext, secondarytext, _NSWarningAlertStyle, "OK")
}
func msgBoxError(title string, text string) {
_msgBox(title, text, _NSCriticalAlertStyle, "OK")
func msgBoxError(primarytext string, secondarytext string) {
_msgBox(primarytext, secondarytext, _NSCriticalAlertStyle, "OK")
}

View File

@ -16,15 +16,15 @@ import (
// GtkWidget *gtkNewMsgBox(GtkMessageType type, GtkButtonsType buttons, char *title, char *text) { GtkWidget *k = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, type, buttons, "%s", (gchar *) title); gtk_message_dialog_format_secondary_text((GtkMessageDialog *) k, "%s", (gchar *) text); return k; }
import "C"
func _msgBox(text string, title string, msgtype C.GtkMessageType, buttons C.GtkButtonsType) (result C.gint) {
func _msgBox(primarytext string, secondarytext string, msgtype C.GtkMessageType, buttons C.GtkButtonsType) (result C.gint) {
ret := make(chan C.gint)
defer close(ret)
uitask <- func() {
ctitle := C.CString(title)
defer C.free(unsafe.Pointer(ctitle))
ctext := C.CString(text)
defer C.free(unsafe.Pointer(ctext))
box := C.gtkNewMsgBox(msgtype, buttons, ctitle, ctext)
cprimarytext := C.CString(primarytext)
defer C.free(unsafe.Pointer(cprimarytext))
csecondarytext := C.CString(secondarytext)
defer C.free(unsafe.Pointer(csecondarytext))
box := C.gtkNewMsgBox(msgtype, buttons, cprimarytext, csecondarytext)
response := C.gtk_dialog_run((*C.GtkDialog)(unsafe.Pointer(box)))
C.gtk_widget_destroy(box)
ret <- response
@ -32,11 +32,11 @@ func _msgBox(text string, title string, msgtype C.GtkMessageType, buttons C.GtkB
return <-ret
}
func msgBox(title string, text string) {
func msgBox(primarytext string, secondarytext string) {
// TODO add an icon?
_msgBox(text, title, C.GtkMessageType(C.GTK_MESSAGE_OTHER), C.GtkButtonsType(C.GTK_BUTTONS_OK))
_msgBox(primarytext, secondarytext, C.GtkMessageType(C.GTK_MESSAGE_OTHER), C.GtkButtonsType(C.GTK_BUTTONS_OK))
}
func msgBoxError(title string, text string) {
_msgBox(text, title, C.GtkMessageType(C.GTK_MESSAGE_ERROR), C.GtkButtonsType(C.GTK_BUTTONS_OK))
func msgBoxError(primarytext string, secondarytext string) {
_msgBox(primarytext, secondarytext, C.GtkMessageType(C.GTK_MESSAGE_ERROR), C.GtkButtonsType(C.GTK_BUTTONS_OK))
}

View File

@ -3,6 +3,7 @@ package ui
import (
"fmt"
"os"
"syscall"
"unsafe"
)
@ -73,23 +74,25 @@ var (
_messageBox = user32.NewProc("MessageBoxW")
)
func _msgBox(lpText string, lpCaption string, uType uint32) (result int) {
func _msgBox(primarytext string, secondarytext string, uType uint32) (result int) {
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa511267.aspx says "Use task dialogs whenever appropriate to achieve a consistent look and layout. Task dialogs require Windows Vista® or later, so they aren't suitable for earlier versions of Windows. If you must use a message box, separate the main instruction from the supplemental instruction with two line breaks."
text := primarytext + "\n\n" + secondarytext
r1, _, err := _messageBox.Call(
uintptr(_NULL),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpText))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpCaption))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(os.Args[0]))),
uintptr(uType))
if r1 == 0 { // failure
panic(fmt.Sprintf("error displaying message box to user: %v\nstyle: 0x%08X\ntitle: %q\ntext:\n%s", err, uType, lpCaption, lpText))
panic(fmt.Sprintf("error displaying message box to user: %v\nstyle: 0x%08X\ntitle: %q\ntext:\n%s", err, uType, os.Args[0], text))
}
return int(r1)
}
func msgBox(title string, text string) {
func msgBox(primarytext string, secondarytext string) {
// TODO add an icon?
_msgBox(text, title, _MB_OK)
_msgBox(primarytext, secondarytext, _MB_OK)
}
func msgBoxError(title string, text string) {
_msgBox(text, title, _MB_OK | _MB_ICONERROR)
func msgBoxError(primarytext string, secondarytext string) {
_msgBox(primarytext, secondarytext, _MB_OK | _MB_ICONERROR)
}

View File

@ -40,7 +40,7 @@ var macCrashTest = flag.Bool("maccrash", false, "attempt crash on Mac OS X on de
func invalidTest(c *Combobox, l *Listbox, s *Stack, g *Grid) {
x := func(what string ) {
if j := recover(); j == nil {
MsgBoxError("test", "%s: no panic", what)
MsgBoxError("test", fmt.Sprintf("%s: no panic", what))
panic("invalid test fail")
} else {
println("got", j.(error).Error())
@ -200,12 +200,16 @@ mainloop:
lb2.Delete(4)
}
case <-b3.Clicked:
MsgBox("List Info",
"cb1: %d %q (len %d)\ncb2: %d %q (len %d)\nlb1: %d %q (len %d)\nlb2: %d %q (len %d)",
f := MsgBox
if c.Checked() {
f = MsgBoxError
}
f("List Info",
fmt.Sprintf("cb1: %d %q (len %d)\ncb2: %d %q (len %d)\nlb1: %d %q (len %d)\nlb2: %d %q (len %d)",
cb1.SelectedIndex(), cb1.Selection(), cb1.Len(),
cb2.SelectedIndex(), cb2.Selection(), cb2.Len(),
lb1.SelectedIndices(), lb1.Selection(), lb1.Len(),
lb2.SelectedIndices(), lb2.Selection(), lb2.Len())
lb2.SelectedIndices(), lb2.Selection(), lb2.Len()))
case <-incButton.Clicked:
prog++
if prog > 100 {

View File

@ -22,9 +22,6 @@ so I don't forget:
- should message box text be selectable on all platforms or only on those that make it the default?
- Listbox/Combobox.Index(n)
- Index(n) is the name used by reflect.Value; use a different one?
- message boxes need cleanup:
- Windows: title: titlebar; text: message box text; no such thing as secondary text
- GTK+ AND Cocoa: title: message box text; text: secondary text; nothing: titlebar
- change sysData.make() so it does not take the initial window text as an argument and instead have the respective Control/Window.make() call sysData.setText() expressly; this would allow me to remove the "no such concept of text" checks from the GTK+ and Mac OS X backends
important things: