Jump to content

click the title bar text to pop-up a menu - now for MS worst OS ever!

Recommended Posts


suppose you want to display only a single large control, e.g. a ListView. you have a lot of data, but it may be viewed on a small-screen device. you care about not wasting screen area, but you need at least a few basic operations. sure you could use a menu bar, but real estate is pricey these days...

inspired by >this - but not even remotely similar in implementation - let's click on the title bar caption text to pop-up a menu! (while clicking on the vacant area of the title bar is used for dragging, as usual).

first let's add a small drop-down-like sign to indicate it's possible to click on the caption text:


(the red line indicates the width of the title bar that when clicked will pop-up a menu. it is slightly extended, to compensate for situations where the font is larger. it is here for illustration only).

the menu is designed as usual, but triggered by registering the WM_SYSCOMMAND message, and checking that the cursor is at the correct position.

unfortunately, Windows XP/2003 do not render extended characters (well or at all), so a standard character was selected for them - see screenshots below. Windows Vista also does a poor job at it. but even more unfortunately, Windows 8 has the title bar caption centered! so here's a quick'n'dirty solution: extend the caption with a lot of whitespaces. this has two side effects - there's the 3-dots sign near the "Minimize" button, and the taskbar icon tooltip is extended. i can live with that...  :)

so this is how it looks:

Windows 8:


Windows Vista:


Windows XP:


Windows 2000 (for the classic theme):


the script (uses >_StringSize by Melba23, but you can set the size fix according to your needs):

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include "StringSize.au3"

Global $nGUI_W = 700, $nGUI_H = 500
Global $sTitle = 'My Program Title'

Global $nOSVersion = _OSVersion()

If $nOSVersion < 6 Then ; not rendering ChrW well
    $sTitle = ' ::  ' & $sTitle
    $sTitle &= ' ' & ChrW(9662)

Global $aTitleWidth = _StringSize($sTitle)
Global $iTitleWidth = 0
If Not @error Then $iTitleWidth = $aTitleWidth[2] + 3 ; ampirical
Global $iTitleOffset = 20 ; ampirical: 16px icon + 4px space

If $nOSVersion > 6.1 Then ; Windows 8, Windows 2012 => "align" caption to left, consider increased font size
    $sTitle &= '                                                                                                                                                                                                                                                                                                                                                                                                                '
    $iTitleOffset = $iTitleOffset * 1.2 ; ampirical
$iTitleWidth = $iTitleWidth * 1.3 ; ampirical


; indicative label for the position and width of titlebar caption text to trigger menu
GUICtrlCreateLabel('', $iTitleOffset, 0, $iTitleWidth, 1)
GUICtrlSetResizing(-1, $GUI_DOCKALL)
GUICtrlSetBkColor(-1, 0xff0000)

Global $gMenu_Dummy = GUICtrlCreateDummy()
Global $gMenu = GUICtrlCreateContextMenu($gMenu_Dummy)

Global $gMenu_Submenu = GUICtrlCreateMenu('Submenu', $gMenu)
Global $gMenu_Option = GUICtrlCreateMenuItem('Option', $gMenu)
Global $bOption = True
GUICtrlSetState(-1, $GUI_CHECKED)
GUICtrlCreateMenuItem('', $gMenu)

For $i = 1 To 5
    GUICtrlCreateMenuItem('Submenu Item ' & $i, $gMenu_Submenu)
    GUICtrlSetState(-1, $GUI_CHECKED)

GUICtrlCreateMenuItem('Item 1', $gMenu)
GUICtrlCreateMenuItem('Item 2', $gMenu)
GUICtrlCreateMenuItem('Item 3', $gMenu)
GUICtrlCreateMenuItem('', $gMenu)

Global $gMenu_About = GUICtrlCreateMenuItem('About', $gMenu)
Global $gMenu_Close = GUICtrlCreateMenuItem('Close', $gMenu)

GUISetState(@SW_SHOW, $hGUI)

Global $msg

While True
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE, $gMenu_Close
        Case $gMenu_Option
            $bOption = Not $bOption
            If $bOption Then
                GUICtrlSetState($gMenu_Option, $GUI_CHECKED)
                GUICtrlSetState($gMenu_Option, $GUI_UNCHECKED)

#region context menu and auxiliary funcs
Func _ContextMenu_ShowMenu($hWnd, $nContextID, $CtrlID = 0, $n_dx = 0, $n_dy = 0)
    ; Show a menu in a given GUI window which belongs to a given GUI ctrl
    Local $arPos[4], $x, $y
    Local $hMenu = GUICtrlGetHandle($nContextID)
    If $CtrlID Then $arPos = ControlGetPos($hWnd, "", $CtrlID)
    $x = $arPos[0] + $n_dx
    $y = $arPos[1] + $arPos[3] + $n_dy
    _ContextMenu_ClientToScreen($hWnd, $x, $y)
    _ContextMenu_TrackPopupMenu($hWnd, $hMenu, $x, $y)
EndFunc   ;==>_ContextMenu_ShowMenu

Func _ContextMenu_ClientToScreen($hWnd, ByRef $x, ByRef $y)
    ; Convert the client (GUI) coordinates to screen (desktop) coordinates
    Local $stPoint = DllStructCreate("int;int")
    DllStructSetData($stPoint, 1, $x)
    DllStructSetData($stPoint, 2, $y)
    DllCall("user32.dll", "int", "ClientToScreen", "hwnd", $hWnd, "ptr", DllStructGetPtr($stPoint))
    $x = DllStructGetData($stPoint, 1)
    $y = DllStructGetData($stPoint, 2)
    ; release Struct not really needed as it is a local
    $stPoint = 0
EndFunc   ;==>_ContextMenu_ClientToScreen

Func _ContextMenu_TrackPopupMenu($hWnd, $hMenu, $x, $y)
    ; Show at the given coordinates (x, y) the popup menu (hMenu) which belongs to a given GUI window (hWnd)
    DllCall("user32.dll", "int", "TrackPopupMenuEx", "hwnd", $hMenu, "int", 0, "int", $x, "int", $y, "hwnd", $hWnd, "ptr", 0)
EndFunc   ;==>_ContextMenu_TrackPopupMenu

Func _WM_SYSCOMMAND($hWnd, $iMsg, $wParam, $lParam) ; to display main menu when click titlebar caption
    #forceref $hWnd, $iMsg, $wParam, $lParam
    Local $iMousePos
    Local $iClientAreaPosX, $iClientAreaPosY
    If $wParam = 0x0000F012 Then
        $iMousePos = MouseGetPos(0)
        _ContextMenu_ClientToScreen($hGUI, $iClientAreaPosX, $iClientAreaPosY)
        If $iMousePos > $iClientAreaPosX + $iTitleOffset And $iMousePos < $iClientAreaPosX + $iTitleOffset + $iTitleWidth Then _ContextMenu_ShowMenu($hWnd, $gMenu)
EndFunc   ;==>_WM_SYSCOMMAND

Func _WM_GETMINMAXINFO($hWnd, $iMsg, $wParam, $lParam) ; to enforce minimum window size
    #forceref $hWnd, $iMsg, $wParam, $lParam
    Local $tagMaxinfo
    If $hWnd = $hGUI Then
        $tagMaxinfo = DllStructCreate("int;int;int;int;int;int;int;int;int;int", $lParam)
        DllStructSetData($tagMaxinfo, 7, $nGUI_W - 100)
        DllStructSetData($tagMaxinfo, 8, $nGUI_H - 100)
        Return 0

Func _OSVersion()
    $sOSVersion = RegRead('HKLM\Software\Microsoft\Windows NT\CurrentVersion', 'CurrentVersion')
    If @error Then Return SetError(1, 0, 0)
    Return Number($sOSVersion)
EndFunc   ;==>_OSVersion
#endregion context menu and auxiliary funcs

the entire thing is as crude as hell, and i'm sure there are many more elegant ways to improve it.


  • Like 3

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now