Shoutbox

HELP - Resizing a child window! - Printable Version

-Shoutbox (https://shoutbox.menthix.net)
+-- Forum: MsgHelp Archive (/forumdisplay.php?fid=58)
+--- Forum: Messenger Plus! for Live Messenger (/forumdisplay.php?fid=4)
+---- Forum: Scripting (/forumdisplay.php?fid=39)
+----- Thread: HELP - Resizing a child window! (/showthread.php?tid=92189)

HELP - Resizing a child window! by whiz on 09-12-2009 at 01:28 PM

This is basically a script which gives you a "command bar" (sort of like a floating deskbar), with various commands.

XML code:
<!-- the parent window -->
 
<Window Id="WndCommandBar_Shell" Version="1">
 
    <Attributes>
        <Caption>Command Bar</Caption>
        <TopMost>true</TopMost>
        <ShowInTaskbar>false</ShowInTaskbar>
    </Attributes>
   
    <TitleBar>
        <AllowMinimize>false</AllowMinimize>
        <AllowClose>false</AllowClose>
    </TitleBar>
   
    <Position Width="188" Height="28">
        <IsAbsolute>true</IsAbsolute>
        <Resizeable Allowed="BothSides">
            <MinWidth>150</MinWidth>
            <MinHeight>28</MinHeight>
        </Resizeable>
    </Position>
   
    <WindowTmpl>
        <Borders Type="Simple"/>
    </WindowTmpl>
 
</Window>

XML code:
<!-- the child window -->
 
<Window Id="WndCommandBar_CMain" Version="1">
 
    <Position Width="188" Height="28">
        <IsAbsolute>true</IsAbsolute>
        <Resizeable Allowed="BothSides">
            <MinWidth>150</MinWidth>
            <MinHeight>28</MinHeight>
        </Resizeable>
    </Position>
   
    <ChildTmpl/>
   
    <Controls>
        <Control xsi:type="ButtonControl" Id="BtnCommands">
            <Position Left="10" Top="0" Width="24">
                <Units>AllPixels</Units>
                <Anchor Vertical="TopBottomFixed"/>
            </Position>
            <Image><Name>Options</Name></Image>
            <Help>Some useful preset commands.</Help>
            <StandardLook Template="Clear"/>
        </Control>
        <Control xsi:type="ButtonControl" Id="BtnContacts">
            <Position Left="35" Top="0" Width="24">
                <Units>AllPixels</Units>
                <Anchor Vertical="TopBottomFixed"/>
            </Position>
            <Image><Name>Contacts</Name></Image>
            <Help>Your Messenger contacts.</Help>
            <StandardLook Template="Clear"/>
        </Control>
        <Control xsi:type="EditControl" Id="EdtCmd">
            <Position Left="60" Top="0" Width="99" Height="24">
                <Units>AllPixels</Units>
                <Anchor Horizontal="LeftRightFixed" Vertical="TopBottomFixed"/>
            </Position>
            <Help>Type a command here...</Help>
        </Control>
        <Control xsi:type="ButtonControl" Id="BtnOk">
            <Position Left="160" Top="0" Width="24">
                <Units>AllPixels</Units>
                <Anchor Horizontal="RightFixed" Vertical="TopBottomFixed"/>
            </Position>
            <Attributes>
                <IsDefault>true</IsDefault>
            </Attributes>
            <Image><Name>Tick</Name></Image>
            <Help>Click to process the command, or press Enter.</Help>
            <StandardLook Template="Clear"/>
        </Control>
    </Controls>
 
</Window>

And that builds it fine, but I want to make it resizable, and when it is resized, only the parent changes.  How do I go about making the child resize with the parent?
RE: HELP - Resizing a child window! by SmokingCookie on 09-12-2009 at 02:24 PM

You need to specify a PlaceHolderElement at the size and position of the child window. Then hook WM_SIZE into your parent window and use PlusWnd::GetElementPos() to retrieve the relative coordinates, which you need to pass to SetWindowPos() in User32.dll.


RE: HELP - Resizing a child window! by whiz on 09-12-2009 at 02:35 PM

quote:
Originally posted by SmokingCookie
You need to specify a PlaceHolderElement at the size and position of the child window.
Okay, done that.

quote:
Originally posted by SmokingCookie
Then hook WM_SIZE into your parent window and use PlusWnd::GetElementPos() to retrieve the relative coordinates, which you need to pass to SetWindowPos() in User32.dll.
I don't know where to start for doing that...  something like this?
Javascript code:
var WndCommandBar_Shell = MsgPlus.CreateWnd("Windows.xml", "WndCommandBar_Shell", 0); // parent
var WndCommandBar_CMain = MsgPlus.CreateChildWnd(WndCommandBar_Shell, "Windows.xml", "WndCommandBar_CMain", 12, 2); // child
Interop.Call("User32", "SetWindowPos", WndCommandBar_Shell.Handle, WndCommandBar_Shell.GetElementPos());


RE: HELP - Resizing a child window! by SmokingCookie on 09-12-2009 at 02:49 PM

First, I was wrong about SetWindowPos();. My apologies. You actually need to use MoveWindow();

Second, you've probably got the first part correct, but the second is kinda.. ya know.. :P

As the scripting docs say, you need to pass the element ID to PlusWnd::GetElementPos(). (It's actually PlusWnd.GetElementPos(ElementID,Type)). So this is what you'll need to do with your PlusWnd:

JScript code:
function RetrievePos(PlusWnd,ElementID) {
    var PosInfo = new Object();
    PosInfo.X = PlusWnd.GetElementPos(ElementID,POSINFO_X /* Predefined within MPL itself */);
    PosInfo.Y = PlusWnd.GetElementPos(ElementID,POSINFO_Y);
    PosInfo.Width = PlusWnd.GetElementPos(ElementID,POSINFO_WIDTH);
    PosInfo.Height = PlusWnd.GetElementPos(ElementID,POSINFO_HEIGHT);
    return PosInfo;
}


Call this function with the parent window object (WndCommandBar_Shell) and the element ID specified in your interface XML.

For MoveWindow(), you need to pass the handle to your child window (WndCommandBar_CMain), its coordinates and size (the information stored in the object returned by my RetrievePos() function) and whether it should be redrawn or not. So it's MoveWindow(hWnd,x,y,width,height,redraw);. Once again, this function is located in User32.dll.

BTW, I recommend redrawing the window through MoveWindow();
RE: HELP - Resizing a child window! by whiz on 09-12-2009 at 03:09 PM

Javascript code:
var WndCommandBar_Shell = MsgPlus.CreateWnd("Windows.xml", "WndCommandBar_Shell", 0);
var WndCommandBar_CMain = MsgPlus.CreateChildWnd(WndCommandBar_Shell, "Windows.xml", "WndCommandBar_CMain", 12, 2);
var PosInfo = RetrievePos(WndCommandBar_Shell, "PlhChild");
Interop.Call("User32", "MoveWindow", WndCommandBar_CMain.Handle, PosInfo.X, PosInfo.Y, PosInfo.Width, PosInfo.Height, true);

Seems to get stuck (Messenger doesn't crash, but the debug doesn't get any further than "Script is starting", and the window appears and then disappears again).
RE: HELP - Resizing a child window! by Matti on 09-12-2009 at 03:32 PM

Actually, SetWindowPos is the right function for this. I've had many trouble before using MoveWindow, and SetWindowPos was always the answer. :P

Anyway, I've done this in my Countdown Live script in the same way as SmokingCookie said. Here's how:

  1. Place the RetrievePos function of SmokingCookie somewhere in your script.
  2. Create your window and child window as you normally would. After creation, register WM_SIZE on your parent.
    Javascript code:
    WndCommandBar_Shell.RegisterMessageNotification(/* WM_SIZE */ 0x5, true);

  3. Create a handler for the message notification event. Check the Message parameter and when you got WM_SIZE, you can resize the child window like so:
    Javascript code:
    // Get the place-holder's position
    var posChild = RetrievePos(WndCommandBar_Shell, "PlhChild");
    // SetWindowPos flags
    var flagsSWP = /* SWP_NOACTIVATE */ 0x10 | /* SWP_NOMOVE */ 0x2;
    // Position the child
    Interop.Call("user32", "SetWindowPos", WndCommandBar_CMain.Handle, 0, 0, 0, posChild.Width, posChild.Height, flagsSWP);
    // Done!

I assume that on creation, the child window's size matches that of the place-holder. If not, execute the code provided for the message notification event also just after registering the notification.

On a side note, here's a nifty trick: when you need to get the new size of the window inside the WM_SIZE handler, you can do this without having to call GetWindowRect! The lParam contains the width in the low-order word and the height in the high-order word, so all you have to do is:
Javascript code:
var wWidth = lParam & 0xFFFF; //Get low-order word
var wHeight = (lParam >> 16); //Get high-order word

And tadaa, you saved yourself another call to the Win32 API! :D

Finally, I managed to beat someone instead of being beaten! :P
RE: HELP - Resizing a child window! by SmokingCookie on 09-12-2009 at 03:33 PM

From line 3: you mustn't move the window by that time already. You need to register WM_SIZE into your parent window (PlusWnd::RegisterMessageNotification()). When WM_SIZE is received (OnWindowIdEvent_MessageNotification()), you need to move it.

* Angry at Matti for being quicker ^o) :P

But I do not see why MoveWindow(); shouldn't work..?


RE: HELP - Resizing a child window! by Matti on 09-12-2009 at 03:42 PM

quote:
Originally posted by SmokingCookie
But I do not see why MoveWindow(); shouldn't work..?
I've tried many times before, but it simply fails to work. Either it throws an unknown exception in the script debugger, or it just doesn't do anything. Feel free to try MoveWindow, but I'm sticking to SetWindowPos. :P
RE: HELP - Resizing a child window! by SmokingCookie on 09-12-2009 at 03:46 PM

It works perfectly fine in my scripts.


RE: HELP - Resizing a child window! by whiz on 09-13-2009 at 09:59 AM

quote:
Originally posted by Matti
  1. Place the RetrievePos function of SmokingCookie somewhere in your script.
  2. Create your window and child window as you normally would. After creation, register WM_SIZE on your parent.
    Javascript code:
    WndCommandBar_Shell.RegisterMessageNotification(/* WM_SIZE */ 0x5, true);

  3. Create a handler for the message notification event. Check the Message parameter and when you got WM_SIZE, you can resize the child window like so:
    Javascript code:
    // Get the place-holder's position
    var posChild = RetrievePos(WndCommandBar_Shell, "PlhChild");
    // SetWindowPos flags
    var flagsSWP = /* SWP_NOACTIVATE */ 0x10 | /* SWP_NOMOVE */ 0x2;
    // Position the child
    Interop.Call("user32", "SetWindowPos", WndCommandBar_CMain.Handle, 0, 0, 0, posChild.Width, posChild.Height, flagsSWP);
    // Done!


I've done all that, and the parent/child windows are loaded, but as soon as I resize the window, the child disappears.  It leaves just an empty parent window...
RE: HELP - Resizing a child window! by Matti on 09-13-2009 at 10:10 AM

quote:
Originally posted by whiz
I've done all that, and the parent/child windows are loaded, but as soon as I resize the window, the child disappears.  It leaves just an empty parent window...
That's odd... Can you pack your script and upload it so we can have a better look at it?
RE: HELP - Resizing a child window! by whiz on 09-13-2009 at 10:33 AM

Attached.


RE: HELP - Resizing a child window! by SmokingCookie on 09-14-2009 at 07:39 AM

I do not exactly have time ATM, but still: you must place the PlaceHolderElement in the parent window, not the child window like you did ;)


RE: HELP - Resizing a child window! by whiz on 09-14-2009 at 03:55 PM

quote:
Originally posted by SmokingCookie
I do not exactly have time ATM, but still: you must place the PlaceHolderElement in the parent window, not the child window like you did ;)
Umm...
XML code:
<Window Id="WndCommandBar_Shell" Version="1">
 
    <Attributes>
        <Caption>Command Bar</Caption>
        <TopMost>true</TopMost>
        <ShowInTaskbar>false</ShowInTaskbar>
    </Attributes>
   
    <TitleBar>
        <AllowMinimize>false</AllowMinimize>
        <AllowClose>false</AllowClose>
    </TitleBar>
   
    <Position Width="186" Height="27">
        <IsAbsolute>true</IsAbsolute>
        <Resizeable Allowed="BothSides">
            <MinWidth>150</MinWidth>
            <MinHeight>27</MinHeight>
        </Resizeable>
    </Position>
   
    <WindowTmpl>
        <Borders Type="Simple"/>
    </WindowTmpl>
   
    <Elements>
        <Element xsi:type="PlaceHolderElement" Id="PhlChild">
            <Position Left="10" Top="0" Width="172" Height="26"/>
        </Element>
    </Elements>
 
</Window>

...I have, haven't I (the parent is actually second in the interface file - the first is the old one, to be ignored)?

EDIT: were you looking at the code in the first post?  :P
RE: HELP - Resizing a child window! by Matti on 09-14-2009 at 05:20 PM

Fixed it!

  • OnWndCommandBar_ShellEvent_MessageNotification always has to return something. Because we want all messages to be processed normally, we always return -1.
  • You defined the element in your XML as "PhlChild" but you're referencing it as "PlhChild"! This is why RetrievePos always gives 0 for position and size.
  • The place-holder needs to size with the window, so it needs anchoring.
  • The place-holder should be the same size as the child window it holds in order to make the child size properly.
Attached is the script package with these fixes included. You still need to resize the other child window as well. Here's a tip: only resize the currently displayed child window, so store the current child in some global variable, size that one when receiving WM_SIZE and swap it when the child changes (don't forget to resize the new child after swapping!).
RE: HELP - Resizing a child window! by SmokingCookie on 09-14-2009 at 05:20 PM

Like I said, I didn't have the time this morning. I had a few hours off at school, so I rush-finished some homework (still too late for school though :$ :P ).

Anyway, seems like I was confused by the window IDs. I'm used to a system like this:

JScript code:
//Some example code demonstrating Window IDs and child IDs
 
var PlusWnd = MsgPlus.CreateWnd("Wnd.xml","WndTest");
var ChildWnd = MsgPlus.CreateChildWnd(PlusWnd,"Wnd.xml","WndTest_Child",0,0,true);


You might wanna try this yourself ;)

And I think I've found the error:

XML code:
    <Elements>
        <Element xsi:type="PlaceHolderElement" Id="PhlChild"> <!-- Check the element ID here -->
            <Position Left="10" Top="0" Width="172" Height="26"/>
        </Element>
    </Elements>


JScript code:
function OnWndCommandBar_ShellEvent_MessageNotification(PlusWnd, Message, wParam, lParam)
{
    if (Message == 0x5)
    {
        var posChild = RetrievePos(WndCommandBar_Shell,"PlhChild"); // Check the element ID here too
        Interop.Call("user32","MoveWindow",WndCommandBar_CMain.Handle,posChild.x,posChild.y,posChild.Width,posChild.Height,true); // Thought this would solve it...
    }
}


That's one common error I've experienced MANY times.. ^0)

* Even more angry at Matti....
AGAIN!! :S :P

RE: HELP - Resizing a child window! by whiz on 09-14-2009 at 05:58 PM

Great, it works!  :P  Except that I installed the script and didn't think to copy all of the changes I had made with the actual workings of the script...  that I've now lost...  :D  Ah, well.

EDIT: I've managed to recover most of my changes from my online backup, which (luckily) hadn't synchronized that bit yet...  :)