123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- // Copyright 2010 The Walk Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // +build windows
- package walk
- import (
- "syscall"
- "unsafe"
- )
- import (
- "github.com/lxn/win"
- )
- const (
- DlgCmdNone = 0
- DlgCmdOK = win.IDOK
- DlgCmdCancel = win.IDCANCEL
- DlgCmdAbort = win.IDABORT
- DlgCmdRetry = win.IDRETRY
- DlgCmdIgnore = win.IDIGNORE
- DlgCmdYes = win.IDYES
- DlgCmdNo = win.IDNO
- DlgCmdClose = win.IDCLOSE
- DlgCmdHelp = win.IDHELP
- DlgCmdTryAgain = win.IDTRYAGAIN
- DlgCmdContinue = win.IDCONTINUE
- DlgCmdTimeout = win.IDTIMEOUT
- )
- const dialogWindowClass = `\o/ Walk_Dialog_Class \o/`
- func init() {
- MustRegisterWindowClass(dialogWindowClass)
- }
- type dialogish interface {
- DefaultButton() *PushButton
- CancelButton() *PushButton
- }
- type Dialog struct {
- FormBase
- result int
- defaultButton *PushButton
- cancelButton *PushButton
- centerInOwnerWhenRun bool
- }
- func NewDialog(owner Form) (*Dialog, error) {
- return newDialogWithStyle(owner, win.WS_THICKFRAME)
- }
- func NewDialogWithFixedSize(owner Form) (*Dialog, error) {
- return newDialogWithStyle(owner, 0)
- }
- func newDialogWithStyle(owner Form, style uint32) (*Dialog, error) {
- dlg := &Dialog{
- FormBase: FormBase{
- owner: owner,
- },
- }
- if err := InitWindow(
- dlg,
- owner,
- dialogWindowClass,
- win.WS_CAPTION|win.WS_SYSMENU|style,
- 0); err != nil {
- return nil, err
- }
- succeeded := false
- defer func() {
- if !succeeded {
- dlg.Dispose()
- }
- }()
- dlg.centerInOwnerWhenRun = owner != nil
- // This forces display of focus rectangles, as soon as the user starts to type.
- dlg.SendMessage(win.WM_CHANGEUISTATE, win.UIS_INITIALIZE, 0)
- dlg.result = DlgCmdNone
- succeeded = true
- return dlg, nil
- }
- func (dlg *Dialog) DefaultButton() *PushButton {
- return dlg.defaultButton
- }
- func (dlg *Dialog) SetDefaultButton(button *PushButton) error {
- if button != nil && !win.IsChild(dlg.hWnd, button.hWnd) {
- return newError("not a descendant of the dialog")
- }
- succeeded := false
- if dlg.defaultButton != nil {
- if err := dlg.defaultButton.setAndClearStyleBits(win.BS_PUSHBUTTON, win.BS_DEFPUSHBUTTON); err != nil {
- return err
- }
- defer func() {
- if !succeeded {
- dlg.defaultButton.setAndClearStyleBits(win.BS_DEFPUSHBUTTON, win.BS_PUSHBUTTON)
- }
- }()
- }
- if button != nil {
- if err := button.setAndClearStyleBits(win.BS_DEFPUSHBUTTON, win.BS_PUSHBUTTON); err != nil {
- return err
- }
- }
- dlg.defaultButton = button
- succeeded = true
- return nil
- }
- func (dlg *Dialog) CancelButton() *PushButton {
- return dlg.cancelButton
- }
- func (dlg *Dialog) SetCancelButton(button *PushButton) error {
- if button != nil && !win.IsChild(dlg.hWnd, button.hWnd) {
- return newError("not a descendant of the dialog")
- }
- dlg.cancelButton = button
- return nil
- }
- func (dlg *Dialog) Result() int {
- return dlg.result
- }
- func (dlg *Dialog) Accept() {
- dlg.Close(DlgCmdOK)
- }
- func (dlg *Dialog) Cancel() {
- dlg.Close(DlgCmdCancel)
- }
- func (dlg *Dialog) Close(result int) {
- dlg.result = result
- dlg.FormBase.Close()
- }
- func firstFocusableDescendantCallback(hwnd win.HWND, lParam uintptr) uintptr {
- widget := windowFromHandle(hwnd)
- if widget == nil || !widget.Visible() || !widget.Enabled() {
- return 1
- }
- style := uint(win.GetWindowLong(hwnd, win.GWL_STYLE))
- // FIXME: Ugly workaround for NumberEdit
- _, isTextSelectable := widget.(textSelectable)
- if style&win.WS_TABSTOP > 0 || isTextSelectable {
- hwndPtr := (*win.HWND)(unsafe.Pointer(lParam))
- *hwndPtr = hwnd
- return 0
- }
- return 1
- }
- var firstFocusableDescendantCallbackPtr = syscall.NewCallback(firstFocusableDescendantCallback)
- func firstFocusableDescendant(container Container) Window {
- var hwnd win.HWND
- win.EnumChildWindows(container.Handle(), firstFocusableDescendantCallbackPtr, uintptr(unsafe.Pointer(&hwnd)))
- return windowFromHandle(hwnd)
- }
- type textSelectable interface {
- SetTextSelection(start, end int)
- }
- func (dlg *Dialog) focusFirstCandidateDescendant() {
- window := firstFocusableDescendant(dlg)
- if window == nil {
- return
- }
- if err := window.SetFocus(); err != nil {
- return
- }
- if textSel, ok := window.(textSelectable); ok {
- textSel.SetTextSelection(0, -1)
- }
- }
- func (dlg *Dialog) Show() {
- if dlg.owner != nil {
- var size Size
- if layout := dlg.Layout(); layout != nil {
- size = layout.MinSize()
- min := dlg.MinSize()
- size.Width = maxi(size.Width, min.Width)
- size.Height = maxi(size.Height, min.Height)
- } else {
- size = dlg.Size()
- }
- ob := dlg.owner.Bounds()
- if dlg.centerInOwnerWhenRun {
- dlg.SetBounds(Rectangle{
- ob.X + (ob.Width-size.Width)/2,
- ob.Y + (ob.Height-size.Height)/2,
- size.Width,
- size.Height,
- })
- }
- } else {
- dlg.SetBounds(dlg.Bounds())
- }
- dlg.FormBase.Show()
- dlg.focusFirstCandidateDescendant()
- }
- func (dlg *Dialog) Run() int {
- dlg.Show()
- if dlg.owner != nil {
- dlg.owner.SetEnabled(false)
- }
- dlg.FormBase.Run()
- return dlg.result
- }
|