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:
parent
6eea59c30a
commit
2fb7056be4
15
dialog.go
15
dialog.go
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
12
test/main.go
12
test/main.go
|
@ -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 {
|
||||
|
|
3
todo.md
3
todo.md
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue