rodrigocfd/windigo

_RunModalLoop doesn't break

Hoto-Cocoa opened this issue · 4 comments

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.

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.

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)
	})
}

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

Thanks! I confirm this issue resolved.