Window.ShowWithin "Modality"

I’m working on a cross-platform app that can have multiple document windows open at once. When a certain process is invoked in one of the windows, I show a dialog with a progress bar. I’m using a sheet window and Window.ShowWithin to display the progress bar. This works great as it blocks access to the current window while the window with the progress bar is open. However, except for the Mac build, this also blocks access to any of the other open document windows. Since the activity in that one window might take a while to complete, I need to be able to access the other document windows in the meantime. This works fine on the Mac as the progress window is showing a sheet window that is modal within the document window that invoked it while on Windows and Linux the progress dialog is shown as a movable modal dialog that is modal to all open windows. Is there any way to restrict the “modality” of a dialog to the window that invoked it?

Use ShowModalWithin

Thanks. I tried that, but it doesn’t seem to make a difference. while the dialog is open, none of the other windows can be moved and none of the controls/menus/etc in the other windows are responsive. Am I missing something?

Dunno since I cant see code etc but we use this all over the IDE with windows defined as Sheets and ShowModalWithin

Make sure you pass the window that the dialog should be modal on as the parameter otherwise you get application modal

I prepared a small demo project to show the issue:

https://www.dropbox.com/s/jz61fsliodvb5sa/ShowWithinTest.xojo_binary_project?dl=0

Once one window opens a dialog with either ShowWithin or ShowModalWithin, the other one becomes inaccessible on Windows while on the Mac this works just fine.

I rolled my own crossplatform “sheet window” a while ago by using a canvas that scrolls down.

Interesting. Do you deactivate all the controls and menus in the window that contains your canvas, or how do you ensure that your “sheet window” is modal?

I think you just found a bug
Looking into this as soon a I can

[quote=305164:@Norman Palardy]I think you just found a bug
Looking into this as soon a I can[/quote]
Thanks! Should I file a bug report?

I filed one internally already

Great!

  • Place an invisible Canvas over the window
  • Return true in the canvas MouseDown event to consume clicks
  • Instead of a dialog, use a ContainerControl.

When you want to display the false dialog, render the canvas visible and display embed the containerControl within it. If all goes well, the canvas will prevent clicks over that window so your container control dialog will be modal.

When dismissing the dialog, close the containercontrol and make the canvas invisible again.

It is probably close to what Markus did.

I created my own show modal method. I create my modal window as a regular document window. I set a variable in the parent window to reference the ‘modal’ window. In the window.activate event I have this code if ModalWindow <> nil then ModalWindow.SetFocus.
I can have multiple child modal windows and the focus is passed down the line to the top most modal window.
For example: MainWindow>OptionsWindow>UserSettingWindow

Sub ShowModalWindow(W as window) ModalWindow = W w.ShowModal ModalWindow = nil End Sub

One other huge benefit is that clicking the parent window brings the modal window (and the parent window) to the front. A regular modal dialog disables the parent window so if the modal window is covered by something else, clicking the parent window leaves you wondering why it ‘don’t do anything’.

Revised Project

That works, but you can still click the buttons and create as many new windows as you want, since the window is not modal.

In real life, you want to disable the buttons on the main window when the “modal” is shown, and reinstate them when it is closed.

I tried the canvas as described above, unfortunately it does not disable buttons. It can be used to show an overlaid shadow, though.

There is another way : cover everything with a ContainerControl, and DrawInto the window in the ContainerControl Paint event, then display the “modal”.

I think also necessary to prevent move of the “modal” out of the window that called it.

I’ve only used this on windows. I know the buttons on the main window are not actually disabled. However no clicks are really ever received because the focus is immediately passed to the ‘modal’ window. The only things That are still doable to the main window are moving the window, and maximizing by double clicking the title bar. Buttons do not receive any action events when clicked.

You would have to do something like this for compatibility on both Mac and Windows.
Sample Project

[quote=305415:@Neil Burkholder]You would have to do something like this for compatibility on both Mac and Windows.
Sample Project[/quote]
Interesting solution. Thanks! Have you verified this on Linux as well?

In Mac this is less an issue, since sheet windows and modal dialogs don’t “bleed” out of their target windows.

The same issue presents in Linux as in Windows : instead of having a child window, a modal dialog becomes a global modal window. It would seem useful to add that to your internal bug report, so both get fixed.

I spent a while reading at https://msdn.microsoft.com/en-us/library/aa984358(v=vs.71).aspx on modal and modeless dialogs.

This phrase implies that the rest of the application will be frozen, which accounts for the current behavior :

What is reported seems not to be a bug at all under Windows.