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.


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
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Create New...