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 package ui
import ( import (
"fmt" // ...
) )
// MsgBox displays an informational message box to the user with just an OK button. // MsgBox displays an informational message box to the user with just an OK button.
func MsgBox(title string, textfmt string, args ...interface{}) { // primaryText should be a short string describing the message, and will be displayed with additional emphasis on platforms that support it.
msgBox(title, fmt.Sprintf(textfmt, args...)) // 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. // 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{}) { // Otherwise, it behaves like MsgBox.
msgBoxError(title, fmt.Sprintf(textfmt, args...)) func MsgBoxError(primaryText string, secondaryText string) {
msgBoxError(primaryText, secondaryText)
} }

View File

@ -26,14 +26,13 @@ var (
_runModal = sel_getUid("runModal") _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{}) ret := make(chan struct{})
defer close(ret) defer close(ret)
uitask <- func() { uitask <- func() {
box := objc_new(_NSAlert) box := objc_new(_NSAlert)
// TODO is this appropriate for title? C.objc_msgSend_id(box, _setMessageText, toNSString(primarytext))
C.objc_msgSend_id(box, _setMessageText, toNSString(title)) C.objc_msgSend_id(box, _setInformativeText, toNSString(secondarytext))
C.objc_msgSend_id(box, _setInformativeText, toNSString(text))
objc_msgSend_uint(box, _setAlertStyle, style) objc_msgSend_uint(box, _setAlertStyle, style)
C.objc_msgSend_id(box, _addButtonWithTitle, toNSString(button0)) C.objc_msgSend_id(box, _addButtonWithTitle, toNSString(button0))
C.objc_msgSend_noargs(box, _runModal) C.objc_msgSend_noargs(box, _runModal)
@ -42,11 +41,11 @@ func _msgBox(title string, text string, style uintptr, button0 string) {
<-ret <-ret
} }
func msgBox(title string, text string) { func msgBox(primarytext string, secondarytext string) {
// TODO _NSInformationalAlertStyle? // TODO _NSInformationalAlertStyle?
_msgBox(title, text, _NSWarningAlertStyle, "OK") _msgBox(primarytext, secondarytext, _NSWarningAlertStyle, "OK")
} }
func msgBoxError(title string, text string) { func msgBoxError(primarytext string, secondarytext string) {
_msgBox(title, text, _NSCriticalAlertStyle, "OK") _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; } // 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" 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) ret := make(chan C.gint)
defer close(ret) defer close(ret)
uitask <- func() { uitask <- func() {
ctitle := C.CString(title) cprimarytext := C.CString(primarytext)
defer C.free(unsafe.Pointer(ctitle)) defer C.free(unsafe.Pointer(cprimarytext))
ctext := C.CString(text) csecondarytext := C.CString(secondarytext)
defer C.free(unsafe.Pointer(ctext)) defer C.free(unsafe.Pointer(csecondarytext))
box := C.gtkNewMsgBox(msgtype, buttons, ctitle, ctext) box := C.gtkNewMsgBox(msgtype, buttons, cprimarytext, csecondarytext)
response := C.gtk_dialog_run((*C.GtkDialog)(unsafe.Pointer(box))) response := C.gtk_dialog_run((*C.GtkDialog)(unsafe.Pointer(box)))
C.gtk_widget_destroy(box) C.gtk_widget_destroy(box)
ret <- response ret <- response
@ -32,11 +32,11 @@ func _msgBox(text string, title string, msgtype C.GtkMessageType, buttons C.GtkB
return <-ret return <-ret
} }
func msgBox(title string, text string) { func msgBox(primarytext string, secondarytext string) {
// TODO add an icon? // 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) { func msgBoxError(primarytext string, secondarytext string) {
_msgBox(text, title, C.GtkMessageType(C.GTK_MESSAGE_ERROR), C.GtkButtonsType(C.GTK_BUTTONS_OK)) _msgBox(primarytext, secondarytext, C.GtkMessageType(C.GTK_MESSAGE_ERROR), C.GtkButtonsType(C.GTK_BUTTONS_OK))
} }

View File

@ -3,6 +3,7 @@ package ui
import ( import (
"fmt" "fmt"
"os"
"syscall" "syscall"
"unsafe" "unsafe"
) )
@ -73,23 +74,25 @@ var (
_messageBox = user32.NewProc("MessageBoxW") _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( r1, _, err := _messageBox.Call(
uintptr(_NULL), uintptr(_NULL),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpText))), uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpCaption))), uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(os.Args[0]))),
uintptr(uType)) uintptr(uType))
if r1 == 0 { // failure 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) return int(r1)
} }
func msgBox(title string, text string) { func msgBox(primarytext string, secondarytext string) {
// TODO add an icon? // TODO add an icon?
_msgBox(text, title, _MB_OK) _msgBox(primarytext, secondarytext, _MB_OK)
} }
func msgBoxError(title string, text string) { func msgBoxError(primarytext string, secondarytext string) {
_msgBox(text, title, _MB_OK | _MB_ICONERROR) _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) { func invalidTest(c *Combobox, l *Listbox, s *Stack, g *Grid) {
x := func(what string ) { x := func(what string ) {
if j := recover(); j == nil { if j := recover(); j == nil {
MsgBoxError("test", "%s: no panic", what) MsgBoxError("test", fmt.Sprintf("%s: no panic", what))
panic("invalid test fail") panic("invalid test fail")
} else { } else {
println("got", j.(error).Error()) println("got", j.(error).Error())
@ -200,12 +200,16 @@ mainloop:
lb2.Delete(4) lb2.Delete(4)
} }
case <-b3.Clicked: case <-b3.Clicked:
MsgBox("List Info", f := MsgBox
"cb1: %d %q (len %d)\ncb2: %d %q (len %d)\nlb1: %d %q (len %d)\nlb2: %d %q (len %d)", 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(), cb1.SelectedIndex(), cb1.Selection(), cb1.Len(),
cb2.SelectedIndex(), cb2.Selection(), cb2.Len(), cb2.SelectedIndex(), cb2.Selection(), cb2.Len(),
lb1.SelectedIndices(), lb1.Selection(), lb1.Len(), lb1.SelectedIndices(), lb1.Selection(), lb1.Len(),
lb2.SelectedIndices(), lb2.Selection(), lb2.Len()) lb2.SelectedIndices(), lb2.Selection(), lb2.Len()))
case <-incButton.Clicked: case <-incButton.Clicked:
prog++ prog++
if prog > 100 { 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? - should message box text be selectable on all platforms or only on those that make it the default?
- Listbox/Combobox.Index(n) - Listbox/Combobox.Index(n)
- Index(n) is the name used by reflect.Value; use a different one? - 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 - 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: important things: