# Attaching Two Windows with setRect()

This little program illustrates a few different window styles, and shows you how one window can be 'attached' to another. Moving the 'Main' window will always cause the 'following' window to move along with it. The original example illustrating this was posted by Brian Broker on the Euphoria mailing list. I've just added a few more event handlers to make it interesting. ( ... or, perhaps, silly ... )

Not too complicated, really! The onEvent[] handler for the 'Main' window simply intercepts a message from Windows, which signals that it has moved. This then moves the 'following' window to the same position it originally had, relative to the 'Main' window.

To see what this program really does, you'll have to to 'play'... by dragging either window around, minimizing either, setting focus to either, etc... in various combinations.

The last window, ( Win3 ) is just here to cover up the desktop. It's been sized to cover the whole screen, minus 31 pixels at the bottom, so the taskbar remains in view.

-- followme.exw

    -- start demo --
    include win32lib.ew
    without warning

    constant
    -- get the screen size for this system.
    CXFULL = w32Func( xGetSystemMetrics, {SM_CXSCREEN} ),
    CYFULL = w32Func( xGetSystemMetrics, {SM_CYSCREEN} ),

    -- our 'Main' window, using one window style
    Win1 = create( Window, "the 'Main' window ?", 0, 200, 200, 250, 100, {WS_DLGFRAME, WS_SYSMENU, WS_MINIMIZEBOX} ),
    Txt1 = create( LText, "Euphoria, and Win32lib", Win1, 10, 10, 200, 22, 0 ),

    -- our 'follower' window, with yet another style, and some buttons
    Win2=create( Window, "...and it's 'follower'", 0, 310, 314, 250, 100, {WS_DLGFRAME,WS_MINIMIZEBOX} ),
    Txt2=create( LText, "...make a great team !", Win2, 10, 10, 200, 22, 0 ),

    -- three buttons in the second 'follower' window.
    Btn1 = create( PushButton, "Hide Text", Win2, 7, 40, 70, 25, 0 ),
    Btn2 = create( PushButton, "Show Text", Win2, 88, 40, 70, 25, 0 ),
    Btn3 = create( PushButton, "Go 'HOME'", Win2, 170, 40, 70, 25, 0 ),

    -- our 'popup' window, covers the desktop
    Win3=create( Window, "", 0, 0, 0, CXFULL, CYFULL-31, {WS_POPUP, WS_DLGFRAME} ),
    Txt3=create( LText, "a 'popup blanker'", Win3, 0, 0, 250, 25, 0 )

    setFont( Txt1, "Comic Sans MS", 12, Normal )
    setFont( Txt2, "Times New Roman", 14, Bold )
    setFont( Txt3, "Times New Roman", 14, Bold )

    ---- ------------------------------------------------------

    -- ..if Win1 receives focus, 'park' Win2 beside it.
    procedure onFocus_Win1( integer self, integer event, sequence params )
    sequence loc1, loc2
      loc1 = getClientPoint(Win1,0,0) -- 'zero' based
      loc2 = getClientPoint(Win2,0,0)
      if loc1[1] != loc2[1] or loc1[2] != loc2[2] then
        setRect( Win2, loc1[1] + 100, loc1[2] + 77, 250, 100, True )
      end if
    end procedure
    setHandler( Win1, w32HGotFocus, routine_id("onFocus_Win1") )

    ----

    -- actually, an event routine for Btn3,  ;-)
    procedure onFocus_Win2()
    sequence loc1, loc2
      loc1 = getClientPoint(Win1,0,0) -- 'zero' based
      loc2 = getClientPoint(Win2,0,0)
      if loc1[1] != loc2[1] or loc1[2] != loc2[2] then
        setRect( Win2, loc1[1] + 100, loc1[2] + 77, 250, 100, True )
      end if
    end procedure

    ----

    -- ..if Win1 is 'dragged', move Win2 along with it.
    procedure onEvent_Win1( integer self, integer event, sequence params )
    integer e_event = params[1]
    atom lParam   lParam = params[3]
    integer x, y

      if e_event = WM_MOVE then
        x = and_bits( lParam, #0000FFFF )          -- low bits
        y = and_bits( lParam, #FFFF0000 ) / #10000 -- high bits
        setRect( Win2, x + 100, y + 77, 250, 100, True )
      end if
    end procedure
    setHandler( Win1, w32HEvent, routine_id( "onEvent_Win1" ) )

    ----

    procedure onClick_Btn1( integer self, integer event, sequence params )
      setVisible(Txt1,False)
      setVisible(Txt2,False)
      setVisible(Txt3,False)
    end procedure
    setHandler( Btn1, w32HClick, routine_id("onClick_Btn1") )

    ----

    procedure onClick_Btn2( integer self, integer event, sequence params )
      setVisible(Txt1,True)
      setVisible(Txt2,True)
      setVisible(Txt3,True)
    end procedure
    setHandler( Btn2, w32HClick, routine_id("onClick_Btn2") )

    ----

    procedure onClick_Btn3( integer self, integer event, sequence params )
      onFocus_Win2()
    end procedure
    setHandler( Btn3, w32HClick, routine_id("onClick_Btn3") )

    ----

    procedure onOpen_Win1( integer self, integer event, sequence params )
      openWindow(Win2,Normal)
    end procedure
    setHandler( Win1, w32HOpen, routine_id("onOpen_Win1") )

    ----

    procedure onOpen_Win2( integer self, integer event, sequence params )
      openWindow(Win3,Normal)
    end procedure
    setHandler( Win2, w32HOpen, routine_id("onOpen_Win2") )

    ----

    procedure keep_fronts( integer self, integer event, sequence params )
      moveZOrder( Win2,  HWND_TOP)
      moveZOrder( Win1,  HWND_TOP)
    end procedure
    --
    setHandler( Win3, w32HGotFocus, routine_id("keep_fronts") )

    --------- start ---------
    WinMain( Win1, Normal )
    ------- end demo --------

Ok, so what's the keep_fronts() procedure for? To illustrate, try the following.
Comment out the line, " moveZOrder( Win2, HWND_TOP) ". If you run the program again, and click on the Win3 background window, Win2 will now disappear behind it. The keep_fronts() procedure just ensures that the two windows you want to see on top, don't get hidden behind Win3. If Win1 got covered up by Win3, there'd be no normal way to [X] the program.

..end of example.

CONTENTS