PlanetSquires Forums

Support Forums => General Board => Topic started by: jermy on August 25, 2025, 10:28:40 AM

Title: Control elements in caption while retaining standard Windows snap layout ?
Post by: jermy on August 25, 2025, 10:28:40 AM
Control elements in caption while retaining standard Windows snap layout
Is this possible? Many Windows apps have this feature, but how do you do it?

Does anyone have any ideas?
Title: Re: Control elements in caption while retaining standard Windows snap layout ?
Post by: José Roca on August 25, 2025, 10:39:14 AM
Which elements? I don't know what you mean.
Title: Re: Control elements in caption while retaining standard Windows snap layout ?
Post by: jermy on August 25, 2025, 11:05:15 AM
Not specifically, but as an example, a menu integrated into the title bar of a window — also known as a custom title bar menu

Notepad also has something similar, tabs in the title bar.
Title: Re: Control elements in caption while retaining standard Windows snap layout ?
Post by: Paul Squires on August 25, 2025, 04:15:27 PM
(https://www.planetsquires.com/images/notepad-tabs.png)
Title: Re: Control elements in caption while retaining standard Windows snap layout ?
Post by: Paul Squires on August 25, 2025, 04:17:16 PM
(https://www.planetsquires.com/images/vscode.png)
Title: Re: Control elements in caption while retaining standard Windows snap layout ?
Post by: José Roca on August 25, 2025, 04:36:20 PM
> Notepad also has something similar, tabs in the title bar.

Notepad has no tabs in the title bar. What it has is a menu.
Title: Re: Control elements in caption while retaining standard Windows snap layout ?
Post by: José Roca on August 25, 2025, 04:43:06 PM
Hi Paul,

Welcome back. Hope you have enjoyed your European travel.
Title: Re: Control elements in caption while retaining standard Windows snap layout ?
Post by: jermy on August 25, 2025, 06:16:46 PM
Quote from: Paul Squires on August 25, 2025, 04:17:16 PM(https://www.planetsquires.com/images/vscode.png)

Such a menu is not very difficult, but how do you get the snap layout under the maximize button to work?
Title: Re: Control elements in caption while retaining standard Windows snap layout ?
Post by: Paul Squires on August 25, 2025, 07:06:31 PM
Quote from: José Roca on August 25, 2025, 04:43:06 PMHi Paul,

Welcome back. Hope you have enjoyed your European travel.

Thanks! Nice trip but always nice to come back home 😁
Title: Re: Control elements in caption while retaining standard Windows snap layout ?
Post by: jermy on August 26, 2025, 03:12:09 PM
Okay, this looks promising.
So far, snaplayout works and there is a close button on the title bar in the non-client area as if it were the client area.

#define _WIN32_WINNT &h0602
#define FB_USE_WINDOWS ' gebruik API bindings in plaats van cross-platform varianten.

#define UNICODE                 ' gebruik Unicode strings
#Include once "windows.bi"
' #include once "win/dwmapi.bi" ' niet beschikbaar in freebasic

' Structs voor DWM (moet vóór de DWM declaraties staan)
Type MARGINS
    cxLeftWidth     As Long
    cxRightWidth    As Long
    cyTopHeight     As Long
    cyBottomHeight  As Long
End Type

' Define needed DWM constants (freebasic dont have header dwmapi.bi)
Const DWMWA_USE_IMMERSIVE_DARK_MODE As DWORD = 20
Const DWMWA_CAPTION_COLOR As DWORD = 35


Extern "windows-ms"
    Declare Function DwmExtendFrameIntoClientArea Lib "dwmapi.dll" (ByVal hwnd As HWND, ByVal pMarInset As Any Ptr) As Long
    Declare Function DwmDefWindowProc Lib "dwmapi.dll" (ByVal hwnd As HWND, ByVal msg As UINT, ByVal wParam As WPARAM, ByVal lParam As LPARAM, ByVal plResult As LRESULT Ptr) As BOOL
    Declare Function DwmSetWindowAttribute Lib "dwmapi.dll" Alias "DwmSetWindowAttribute" (ByVal hwnd As HWND, ByVal dwAttribute As DWORD, ByVal pvAttribute As Any Ptr, ByVal cbAttribute As DWORD) As HRESULT
End Extern

DECLARE FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, BYVAL hPrevInstance AS HINSTANCE, BYVAL szCmdLine AS ZSTRING PTR, BYVAL nCmdShow AS LONG) AS LONG

   'run the app
   END WinMain(GetModuleHandleW(NULL), NULL, COMMAND(), SW_NORMAL)

FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

    Static margins As MARGINS = (0, 0, 60, 0)
    Static border_thickness As RECT = (5, 5, 5, 5)
    Dim lResult As LRESULT

    Select Case uMsg
        Case WM_NCCREATE
            ' lParam is een pointer naar CREATESTRUCT
            ' In FreeBASIC kun je direct casten
            Dim pCreate As CREATESTRUCT Ptr = Cast(CREATESTRUCT Ptr, lParam)
            Dim hInst As HINSTANCE = pCreate->hInstance
            Return 1

        Case WM_NCCALCSIZE
            If wParam <> 0 Then
                Dim sz As NCCALCSIZE_PARAMS Ptr = Cast(NCCALCSIZE_PARAMS Ptr, lParam)
                sz->rgrc(0).left += border_thickness.left
                sz->rgrc(0).right -= border_thickness.right
                sz->rgrc(0).bottom -= border_thickness.bottom
            Else
                Dim sz As RECT Ptr = Cast(RECT Ptr, lParam)
                sz->left += border_thickness.left
                sz->right -= border_thickness.right
                sz->bottom -= border_thickness.bottom
            End If
            Return 0

        Case WM_CREATE
            ' DWM frame uitbreiden
            Dim hr As Long
                hr = DwmExtendFrameIntoClientArea(hwnd, @margins)
             

            ' Knop aanmaken
            CreateWindowExW(0, "Button", "Close", WS_CHILD Or WS_VISIBLE Or WS_TABSTOP, 25, 5, 300, 100, hwnd, Cast(HMENU, IDCANCEL), GetModuleHandle(0), 0)
            Return DefWindowProcW(hwnd, uMsg, wParam, lParam)

        Case WM_COMMAND
            Select Case LoWord(wParam)
                Case IDCANCEL
                    PostQuitMessage(0)
            End Select
        return 0


        Case WM_NCHITTEST
            ' DWM standaardverwerking
            If DwmDefWindowProc(hwnd, uMsg, wParam, lParam, @lResult) Then
                Return lResult
            End If
            lResult = DefWindowProc(hwnd, uMsg, wParam, lParam)
            If lResult = HTCLIENT Then
                Dim pt As POINT
                pt.x = LoWord(lParam)
                pt.y = HiWord(lParam)
                ScreenToClient(hwnd, @pt)
                If pt.y < border_thickness.top Then Return HTTOP
                If pt.y < margins.cyTopHeight Then Return HTCAPTION
            End If
            Return lResult
    End Select

   ' // Default processing of Windows messages
   FUNCTION = DefWindowProcW(hWnd, uMsg, wParam, lParam)

END FUNCTION

' Functie om RGB naar BGR DWORD (COLORREF) te converteren
Function ColorToBgrDWORD(ByVal r As UByte, ByVal g As UByte, ByVal b As UByte) As DWORD
    Return (CUInt(b) Shl 16) Or (CUInt(g) Shl 8) Or CUInt(r)
End Function

FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, BYVAL hPrevInstance AS HINSTANCE, BYVAL szCmdLine AS ZSTRING PTR, BYVAL nCmdShow AS LONG) AS LONG
    Dim CLASS_NAME As WString * 64 = "CustomTitlebarWindow"
    Dim wc As WNDCLASSW
    wc.lpfnWndProc = @wndproc
    wc.hInstance = GetModuleHandleW(0)
    wc.lpszClassName = StrPtr(CLASS_NAME)
    wc.hCursor = LoadCursor(0, IDC_ARROW)
    wc.hbrBackground = Cast(HBRUSH, COLOR_WINDOW + 1)

    RegisterClassW(@wc)

    Dim hWndMain As HWND
      hWndMain = CreateWindowExW(0, StrPtr(CLASS_NAME), "Button on Titlebar + Snap Layouts", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, 0, 0, wc.hInstance, 0)

   ' Enable dark mode title bar (if supported)
    Dim dark As BOOL: dark = TRUE
    DwmSetWindowAttribute(hWndMain, DWMWA_USE_IMMERSIVE_DARK_MODE, @dark, SizeOf(dark))

   ' Set caption color
    Dim activeCaption As DWORD = ColorToBgrDWORD(31, 31, 31)
    DwmSetWindowAttribute(hWndMain, DWMWA_CAPTION_COLOR, @activeCaption, SizeOf(activeCaption))

    ShowWindow(hWndMain, SW_SHOWNORMAL)
    UpdateWindow(hWndMain)

    ' // Dispatch Windows messages
   DIM uMsg AS MSG
   WHILE (GetMessageW(@uMsg, NULL, 0, 0) <> FALSE)
      IF IsDialogMessageW(hWndMain, @uMsg) = 0 THEN
         TranslateMessage(@uMsg)
         DispatchMessageW(@uMsg)
      END IF
   WEND

   FUNCTION = uMsg.wParam

END FUNCTION


A canvas (STATIC) will be needed in the client area because the real title bar is not intended for custom drawing and you don't have reliable, modern drawing functionality there.