rodrigocfd / windigo

Windows API and GUI in idiomatic Go.
https://pkg.go.dev/github.com/rodrigocfd/windigo
MIT License
417 stars 23 forks source link

_RunModalLoop doesn't break #20

Closed Hoto-Cocoa closed 1 year ago

Hoto-Cocoa commented 1 year ago

If I show modal window, modal loop doesn't break even window closed/destroyed.

Here is reproducible code:

package main

import (
    "github.com/rodrigocfd/windigo/ui"
    "github.com/rodrigocfd/windigo/win"
    "github.com/rodrigocfd/windigo/win/co"
)

func main() {
    window := ui.NewWindowMain(
        ui.WindowMainOpts().
            Title("Test").
            ClientArea(win.SIZE{Cx: 800, Cy: 600}),
    )

    button := ui.NewButton(window, ui.ButtonOpts().
        Position(win.POINT{X: 10, Y: 10}).
        Size(win.SIZE{Cx: 100, Cy: 30}).
        Text("Open Modal"))

    button.On().BnClicked(func() {
        modal := ui.NewWindowModal(ui.WindowModalOpts().
            Title("Modal").
            ClientArea(win.SIZE{Cx: 300, Cy: 300}))

        button := ui.NewButton(modal, ui.ButtonOpts().
            Position(win.POINT{X: 10, Y: 10}).
            Size(win.SIZE{Cx: 100, Cy: 30}).
            Text("Close"))

        edit := ui.NewEdit(modal, ui.EditOpts().
            Position(win.POINT{X: 10, Y: 50}).
            Size(win.SIZE{Cx: 280, Cy: 20}).
            Text("Hello, world!"))

        button.On().BnClicked(func() {
            modal.Hwnd().DestroyWindow()
        })

        modal.On().WmDestroy(func() {
            window.Hwnd().EnableWindow(true)

            window.Hwnd().MessageBox(edit.Text(), "Input", co.MB_OK|co.MB_ICONINFORMATION)
        })

        modal.ShowModal(window)

        window.Hwnd().MessageBox("Closed", "Modal", co.MB_OK|co.MB_ICONINFORMATION)
    })

    window.RunAsMain()
}

I can see Input message box, but not Modal message box. I was trying to implement a function that returns input value as string after modal closed, but It never returns.

I digged down windigo, and I could check the hWnd value doesn't changed in _RunModalLoop function even modal closed. Maybe this is the problem, but I don't know how to fix this, so I open this Issue instead of Pull Request.

Please let me know If my code is wrong. Thanks for the creating windigo.

rodrigocfd commented 1 year ago

The problem is that you're making a mess with DestroyWindow and WmDestroy. But in order to better understand and control what's going on, I divided your program into 3 files: main.go, WndMain.go and WndModal.go. Each one takes care of 1 thing.

  1. Program entry point: main.go
package main

import (
    "runtime"
)

func main() {
    runtime.LockOSThread()

    mainWindow := NewWndMain()
    mainWindow.Run()
}
  1. Main window: WndMain.go
package main

import (
    "github.com/rodrigocfd/windigo/ui"
    "github.com/rodrigocfd/windigo/win"
)

// WndMain is the main application window.
type WndMain struct {
    wnd     ui.WindowMain
    btnOpen ui.Button
}

// WndMain constructor.
func NewWndMain() *WndMain {
    wnd := ui.NewWindowMain(
        ui.WindowMainOpts().
            Title("Test").
            ClientArea(win.SIZE{Cx: 800, Cy: 600}),
    )

    mainWindow := &WndMain{
        wnd: wnd,
        btnOpen: ui.NewButton(
            wnd,
            ui.ButtonOpts().
                Position(win.POINT{X: 10, Y: 10}).
                Size(win.SIZE{Cx: 300, Cy: 300}).
                Text("Open Modal"),
        ),
    }

    mainWindow.events()
    return mainWindow
}

// WndMain will run.
func (me *WndMain) Run() {
    me.wnd.RunAsMain()
}

// WndMain events are attached here.
func (me *WndMain) events() {
    me.btnOpen.On().BnClicked(func() {
        modal := NewWndModal()
        modal.Show(me.wnd)
    })
}
  1. Modal window: WndModal.go
package main

import (
    "github.com/rodrigocfd/windigo/ui"
    "github.com/rodrigocfd/windigo/win"
    "github.com/rodrigocfd/windigo/win/co"
)

// WndModal is the modal window, opened by WndMain.
type WndModal struct {
    wnd      ui.WindowModal
    btnClose ui.Button
    edit     ui.Edit
}

// WndModal constructor.
func NewWndModal() *WndModal {
    wnd := ui.NewWindowModal(
        ui.WindowModalOpts().
            Title("Modal").
            ClientArea(win.SIZE{Cx: 300, Cy: 300}),
    )

    modalWindow := &WndModal{
        wnd: wnd,
        btnClose: ui.NewButton(
            wnd,
            ui.ButtonOpts().
                Position(win.POINT{X: 10, Y: 10}).
                Size(win.SIZE{Cx: 100, Cy: 30}).
                Text("Close"),
        ),
        edit: ui.NewEdit(
            wnd,
            ui.EditOpts().
                Position(win.POINT{X: 10, Y: 50}).
                Size(win.SIZE{Cx: 280, Cy: 20}).
                Text("Hello, world!"),
        ),
    }

    modalWindow.events()
    return modalWindow
}

// WndModal will be shown; blocks until the modal is closed.
func (me *WndModal) Show(parent ui.AnyParent) {
    me.wnd.ShowModal(parent)
}

// WndModal events are attached here.
func (me *WndModal) events() {
    me.btnClose.On().BnClicked(func() {
        me.wnd.Hwnd().SendMessage(co.WM_CLOSE, 0, 0)
    })
}

Although longer, such code structure is much more scalable, allowing your program to grow in complexity while being maintainable.

Hoto-Cocoa commented 1 year ago

Thanks for the advise.

Sorry for asking questions, but why this code not works? I think the message box should appear after modal closed, but It doesn't appear.

// WndMain events are attached here.
func (me *WndMain) events() {
    me.btnOpen.On().BnClicked(func() {
        modal := NewWndModal()
        modal.Show(me.wnd)
        me.wnd.Hwnd().MessageBox("Modal closed.", "Test", co.MB_ICONINFORMATION)
    })
}
rodrigocfd commented 1 year ago

This time you found a bug. The modal loop was not being terminated correctly in some cases. It's fixed now, thank you.

Hoto-Cocoa commented 1 year ago

Thanks! I confirm this issue resolved.