MrBcx's Control AutoResizer

Started by MrBcx, November 08, 2024, 02:38:03 PM

Previous topic - Next topic

Quin

This is really neat stuff, especially for someone trying to develop native Win32 apps with professional looking GUIs that certainly don't look very professional when I first start with them... :D
Thanks as always for all your hard work MrBcx, this works great!

MrBcx

#4
I updated my code in the opening post. 

The problem concerns how Windows draws GroupBoxes, thus affecting the child windows inside them.

My fix is to hide them while the resize handler is doing its work and then re-show them.

It's not perfect but likely perfect enough. Tested using the EZ_GUI demo.





airr

I had written something similar to the below for another language, maybe it will give you some ideas?  I've only tested this quick and dirty adaptation with an INPUT, BUTTON, and a STATUS.

Code (air_resize.inc) Select


Const akLEFT       =   1
Const akRIGHT      =   2
Const akTOP        =   4
Const akBOTTOM     =   8

Function EnumChildProc(hChild As HWND, lParam  As LPARAM) As Bool
    Dim as Int tmp = 0
    ' Get the stored anchor value
    Dim As DWORD anchor = (DWORD)GetProp(hChild, "WindowAnchor")
    If Not anchor Then Return TRUE  ' Skip if no anchor set
   
    ' Get parent window size from lParam
    Dim As Int parentWidth = LOWORD(lParam)
    Dim As Int parentHeight = HIWORD(lParam)
   
    ' Get current position and size
    Dim As RECT rc
    GetWindowRect(hChild, &rc)
    MapWindowPoints(NULL, GetParent(hChild), (LPPOINT)&rc, 2)
   
    Dim As Int x = rc.left
    Dim As Int y = rc.top
    Dim As Int width = rc.right - rc.left
    Dim As Int height = rc.bottom - rc.top

    Dim As RECT siblingRect
    Dim As HWND hwndSibling = GetNextWindow(hChild, GW_HWNDNEXT);

    ' if there is an object set akRight to the right of
    ' the current child object, get it's width
    If hwndSibling And (UINT)GetProp(hwndSibling, "WindowAnchor") & akRIGHT Then
        GetWindowRect(hwndSibling, &siblingRect)
        MapWindowPoints(NULL, GetParent(hChild), (LPPOINT)&siblingRect, 2)
        tmp = siblingRect.right - siblingRect.left
    End If
   
    ' horizontal anchoring
    If (anchor & akLEFT) And (anchor & akRIGHT) Then
        width = parentWidth - (x * 2) - tmp - 10
    ElseIf (anchor & akRIGHT) Then
        x = parentWidth - width - 10 ' Right margin
    End If
   
    ' vertical anchoring
    If (anchor & akTOP) AND (anchor & akBOTTOM) Then
        height = parentHeight - y * 2
    ElseIf (anchor & akBOTTOM) Then
        y = parentHeight - height - 10 ' Bottom margin
    End If
   
    ' Move/resize the child
    SetWindowPos(hChild, NULL, x, y, width, height, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS)
   
    Return TRUE
End Function

Sub Anchor(hWnd As HWND, Anchor as UINT)
    SetProp(hWnd, "WindowAnchor", (HANDLE)Anchor)
End Sub



Code (demo.bas) Select

GUI "RESIZE_TEST", Pixels

$INCLUDE "air_resize.inc"

Dim As Control Form1, Input1, Button1, Stat1

SUB FORMLOAD
    Form1   = BCX_FORM("Resize Test"      , 0,   0, 310, 250)
    Input1  = BCX_INPUT("", Form1, 5000, 10, 10, 220, 24)
    Button1 = BCX_BUTTON("Click", Form1, 5001, 240, 10, 50, 24)
    Stat1   = BCX_STATUS("Ready", Form1)

    Anchor(Button1, akRIGHT)
    Anchor(Input1, akLEFT Or akRIGHT)
    Anchor(Stat1, akLEFT Or akRIGHT)

    CENTER(Form1)
    SHOW(Form1)
END SUB


BEGIN EVENTS
    SELECT CASE CBMSG

        CASE WM_SIZE
            EnumChildWindows(CBHWND, EnumChildProc, lParam)
            Return 0

    END SELECT
END EVENTS



AIR.

airr

Good start, there are some tearing issues though.  See attached screenshot.

AIR.

MrBcx

#1
Super lightweight and mostly automatic AutoResizer


1) Only works with single Form apps containing a maximum of 100 controls

2) Call StoreInitialControlDimensions(MainForm) >before< SHOW (MainForm)

3) In EVENTS LOOP, under WM_SIZE, CALL AutoResize_Handler(CBLPARAM)



'*************************************************************************
'                      MrBcx's Automatic Control Resizer
'                      November 2024         MIT License
'*************************************************************************
' 1) Only works with single Form apps containing a maximum of 100 controls
' 2) Call StoreInitialControlDimensions(MainForm) >before< SHOW (MainForm) 
' 3) In EVENTS LOOP, under WM_SIZE, CALL AutoResize_Handler(CBLPARAM)
'*************************************************************************

TYPE ControlData
    ' store initial positions/sizes of controls
    hWnd AS HWND
    initX AS LONG
    initY AS LONG
    initWidth AS LONG
    initHeight AS LONG
END TYPE


SUB StoreInitialControlDimensions(FormHwnd AS HWND)
    '**********************************************************************************
    GLOBAL ControlList[100] AS ControlData  ' Array to hold control data
    GLOBAL ControlCount AS LONG             ' Store initial dimensions of each control
    GLOBAL InitWidth AS LONG, InitHeight AS LONG
    '**********************************************************************************
    DIM r AS RECT
    DIM h AS HWND
    DIM pt[202] AS POINT  ' sized for scalability, supports up to 100 controls

    ' Store initial BCX form dimensions
    InitWidth  = GETDIMENSION("width",  Form1, TRUE) - (10 * BCX_SCALEX)
    InitHeight = GETDIMENSION("height", Form1, TRUE) - (20 * BCX_SCALEY)
    ControlCount = 0

    h = GetWindow(FormHwnd, GW_CHILD)
    WHILE h <> 0
        INCR ControlCount
        GetWindowRect(h, &r)

        ' Map RECT corners to client coordinates using POINT array
        pt[(ControlCount - 1) * 2 + 1].x = r.left
        pt[(ControlCount - 1) * 2 + 1].y = r.top
        pt[(ControlCount - 1) * 2 + 2].x = r.right
        pt[(ControlCount - 1) * 2 + 2].y = r.bottom
        MapWindowPoints(0, FormHwnd, &pt[(ControlCount - 1) * 2 + 1], 2)

        ' Store the mapped dimensions in ControlList
        ControlList[ControlCount].hWnd = h
        ControlList[ControlCount].initX = pt[(ControlCount - 1) * 2 + 1].x
        ControlList[ControlCount].initY = pt[(ControlCount - 1) * 2 + 1].y
        ControlList[ControlCount].initWidth = pt[(ControlCount - 1) * 2 + 2].x - pt[(ControlCount - 1) * 2 + 1].x
        ControlList[ControlCount].initHeight = pt[(ControlCount - 1) * 2 + 2].y - pt[(ControlCount - 1) * 2 + 1].y

        h = GetWindow(h, GW_HWNDNEXT)
    WEND
END SUB



SUB ResizeControls(FormHwnd AS HWND, NewWidth AS LONG, NewHeight AS LONG)
    DIM AS LONG newX, newY, newW, newH
    FOR INT i = 1 TO ControlCount
        WITH ControlList[i]
            HIDE(.hWnd)
            newX = (.initX * NewWidth) / InitWidth
            newY = (.initY * NewHeight) / InitHeight
            newW = (.initWidth * NewWidth) / InitWidth
            newH = (.initHeight * NewHeight) / InitHeight
            MoveWindow(.hWnd, newX, newY, newW, newH, TRUE)
            SHOW(.hWnd)
        END WITH
    NEXT
END SUB


SUB AutoResize_Handler(lParam AS LPARAM)
    DIM AS LONG newWidth, newHeight
    newWidth = LOWORD(lParam)
    newHeight = HIWORD(lParam)
    CALL ResizeControls(Form1, newWidth, newHeight)
END SUB