MoI discussion forum
MoI discussion forum

Full Version: API issues moving windows

From: Joe (CTKJOSE)
8 Jan 2023   [#1]
I got myself MoI for Xmas and currently attempting to write a plugin. (I'm on a Mac (Monterey) )

1. In my plugin I create windows with `openDialog` but when I try to move them with `window.move(x,y)` the move doesn't work. All windows are loading the same URL but with different params in the URL arguments. I tried to move them from with JS but it doesn't work. (Same issues with V5 Beta.)

Any pointers or work arounds will be appreciated...
From: Michael Gibson
8 Jan 2023   [#2] In reply to [#1]
Hi Joe, can you please post an example script that is not working as expected?

- Michael
From: Michael Gibson
8 Jan 2023   [#3] In reply to [#1]
One thing to note is that if the given x,y coordinates are not visible on the screen the window move will be ignored.

- Michael
From: Joe (CTKJOSE)
8 Jan 2023   [#4] In reply to [#2]
Hi

Im gonna clean up my code and uploaded to GitHub, in the meantime the gist is the following:

Im trying to stack new notifications and also avoid having the notifications popup in the middle of the work area. These are passive notifications. Some of them will auto close, other may include actionable items.

code:
var aView = moi.ui.createDialog( 'moi://appdata/libs/PluginSDK/tplNotification.html?id=' + this.notID, 'defaultWidth:350,defaultHeight:100', moi.ui.mainWindow );
if ( aView ){

//save the notification view, so I can reorder them when one is closed
var y = 100;
aView.window.move(1, y);
}


I tried very simple examples and using manual values without any luck.

I notice that the dialogs do remember their size, but always open in the center of the workspace
From: Michael Gibson
8 Jan 2023   [#5] In reply to [#4]
Hi Joe, it's probably because calling moi.ui.createDialog() is asynchronous. When you're calling

So probably you'd need to put the call to .move(x,y) inside the dialog in an onload="" handler.

What's probably happening is the call to .move(1, y) is happening before the dialog is finished loading and it is going to position the dialog when it is finished loading and that then wipes out the initial move.

- Michael
From: Michael Gibson
8 Jan 2023   [#6] In reply to [#4]
Hi Joe, re: moving window - maybe what I should do is if a script calls .move(x,y) on a window before it's been loaded and displayed I can store that and position the window there after it's been loaded instead of putting it in the default position.

- Michael
From: Joe (CTKJOSE)
9 Jan 2023   [#7] In reply to [#5]
i already tried that, using a setTimeout in the dialog’s html after/before the windows load/ready event.
From: Michael Gibson
9 Jan 2023   [#8] In reply to [#7]
Hi Joe, so a dialog will fire a 'display' UI event when it's finished loading so it should be possible to wait for that to happen before calling .move(x,y) on it.

Try like this:
code:
var dlg = moi.ui.createDialog( '<html><body class="DialogBody"><div>testing</div><div>testing</div><div>testing</div><moi:DialogClose/></body></html>' );

while ( dlg.waitForEvent() )
{
    if ( dlg.event == "display" )
        break;
}

dlg.window.move( 10, 10 );


I have also got it set up for the next beta so that if a script calls .move() or .resize() on a window before it has finished loading it will record the given position or size and apply it after it has loaded.

- Michael
From: Joe (CTKJOSE)
23 Jan 2023   [#9] In reply to [#8]
@Michael
code:
var dlg = moi.ui.createDialog( '<html><body class="DialogBody"><div>testing...</div><moi:DialogClose/></body></html>', 'resizable,defaultWidth:350,defaultHeight:200' );

while ( dlg.waitForEvent() ){
    if ( dlg.event == "display" )
        break;
}

dlg.window.move( 10, 10 );


1. I was wondering if you can share a bit more info on what's going on behind the scene. I'm trying to write my plugin with more asynchronous code, promises, and callbacks, and attempting to use `createDialog` for something it was not meant for, ie: panels and toolbars.

I can get `resize()` to work but not `move()`...

After doing some testing I notice (speculating) the following:

- The HTML view (QT WebView) is loaded and all of the rendering and DOM events are completed, prior to the dialog's "display" event. You can manipulate DOM/window without issues at this point.

- I'm speculating that the window/QT layout is modified after the WebView's triggered the load completed, something along the lines of `restoreGeometry`, `restoreState`. The window is centered (relative to the main) (as an expected behavior of a dialog) and window dimensions are restored.

- After that, the `display` event is triggered.

- You can handle the "Esc" in javascript, it always dismisses the dialog.

2. I have a couple of wishes/ramblings!

It would be cool if you add a couple of signals to your QTObjects, that would make this type of interaction more event-driven.

In createDialog() there could be additional window parameters to control its behavior, or maybe a new openWindow() function like

code:
var dialog = moi.ui.openWindow(html, 'resizeable,defaultWidth:380,defaultHeight:420,isModal:true,isCentered:true,style:Dialog,title:My Dialog', moi.ui.mainWindow );


In this example, `isModal ` means that it blocks interaction with MoI until it is dismissed (Qt::ApplicationModal).

Style control the layout and window type like Qt::Window, Qt::Dialog, Qt::Tool, Qt::Popup, etc. Allowing the FramelessWindowHint would be cool to do HUDs and overlays.

===EDITS ====

More observations

`defaultWidth` and `defaultHeight` only work the first time the dialog is used, subsequent calls to the same code/command ignore these values. They work if the actual HTML contents or the URL changes from the previous call.

re
>> I have also got it set up for the next beta so that if a script calls .move() or .resize() on a window before it has finished loading it will record the given position or size and apply it after it has loaded.

I actually did that, I tried two approaches, one would concatenate JS code that would be executed after the `display` event, sort of like a jquery "ready" function. The other would store properties in the window object with a flag to resize/move. Among others, the object would have things like minWidth and minHeight to limit `resize` (you can not change the size by code unless the window has resizable property).

The `resize()` works, but `move()` never worked.
From: Michael Gibson
23 Jan 2023   [#10] In reply to [#9]
Hi Joe,

re:
> I can get `resize()` to work but not `move()`...

Is it possible that the coordinates you are giving to move() are not at a visible point on the desktop window? Maybe the y coordinate in particular is underneath the Mac top menu bar.

What happens if you try running this version:

code:
var dlg = moi.ui.createDialog( '<html><body class="DialogBody"><div>testing...</div><moi:DialogClose/></body></html>', 'resizable,defaultWidth:350,defaultHeight:200' );

while ( dlg.waitForEvent() ){
    if ( dlg.event == "display" )
        break;
}

dlg.window.move( 100, 100 );

> In this example, `isModal ` means that it blocks interaction with MoI until it is dismissed (Qt::ApplicationModal).

You can do a modal dialog by calling dialog.window.doModal(); after moi.ui.createDialog(). That will call setWindowModality( Qt::WindowModal );


> Style control the layout and window type like Qt::Window, Qt::Dialog, Qt::Tool, Qt::Popup, etc. Allowing
> the FramelessWindowHint would be cool to do HUDs and overlays.

You can use var menu = moi.ui.showMenu() to create a Qt::Popup window with FramelessWindowHint instead of a dialog.

The options you can currently set for a dialog are:
resizable, fixedWidth, fixedHeight, defaultWidth, defaultHeight, and noCloseButton.

- Michael
From: Joe (CTKJOSE)
24 Jan 2023   [#11] In reply to [#10]
@Michael

Thanks for directing me in the right direction. My values were always positive, but kept trying and figure out the issue is MacOS's Menu Bar.

I have to keep my "Y" above 24pt (in Big Sur and above).