Control elements in caption while retaining standard Windows snap layout ?

Started by jermy, August 25, 2025, 10:28:40 AM

Previous topic - Next topic

jermy

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?

José Roca


jermy

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.

Paul Squires

Paul Squires
PlanetSquires Software

Paul Squires

Paul Squires
PlanetSquires Software

José Roca

> Notepad also has something similar, tabs in the title bar.

Notepad has no tabs in the title bar. What it has is a menu.

José Roca

Hi Paul,

Welcome back. Hope you have enjoyed your European travel.

jermy

Quote from: Paul Squires on August 25, 2025, 04:17:16 PM

Such a menu is not very difficult, but how do you get the snap layout under the maximize button to work?

Paul Squires

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 😁
Paul Squires
PlanetSquires Software

jermy

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.