mCtrl is open-source C library providing set of additional user interface controls for Windows, intended to be complementary to standard Win32API controls from USER32.DLL and COMCTL32.DLL.
Web site: http://www.mctrl.org/
The controls look nice and useful. Some of the examples use the antiquated method of resource dialogs and obsolete functions like LoadIcon. Here I'm using LoadMetric, that I have needed to wrap because the library provided by the FB headers don't support it (yet one more!). I will add AfxLoadMetric to AfxWin because I don't think it will be supported anytime soon.
Note: To use the controls of this library you must link a resource file with a manifest.
' ########################################################################################
' Microsoft Windows
' File: mCtrl_SplitButton.fbtpl
' Contents: mCtrl split button example
' Compiler: FreeBasic 32 & 64 bit
' Copyright (c) 2016 Jose Roca. Freeware. Use at your own risk.
' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
' EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
' MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ########################################################################################
#define unicode
#define _WIN32_WINNT &h0602
#INCLUDE ONCE "Afx/CWindow.inc"
USING Afx.CWindowClass
#INCLUDE ONCE "mCtrl.bi"
' $FB_RESPATH = "FBRES.rc"
#define ID_BUTTON_ICON_1 100
#define ID_BUTTON_ICON_2 101
#define ID_BUTTON_SPLIT_1 102
#define ID_BUTTON_SPLIT_2 103
DECLARE FUNCTION WndProc (BYVAL hWnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
DECLARE FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, _
BYVAL hPrevInstance AS HINSTANCE, _
BYVAL szCmdLine AS ZSTRING PTR, _
BYVAL nCmdShow AS LONG) AS LONG
END WinMain(GetModuleHandleW(NULL), NULL, COMMAND(), SW_NORMAL)
' ========================================================================================
' Loads a specified icon resource with a client-specified system metric.
' See: https://msdn.microsoft.com/en-us/library/windows/desktop/bb775701(v=vs.85).aspx
' ========================================================================================
PRIVATE FUNCTION AfxLoadIconMetric (BYVAL hinst AS HINSTANCE, BYVAL pszName AS PCWSTR, BYVAL lims AS LONG, BYVAL phico AS HICON PTR) AS HRESULT
DIM AS ANY PTR pLib = DyLibLoad("Comctl32.dll")
IF pLib = NULL THEN EXIT FUNCTION
DIM pLoadIconMetric AS FUNCTION (BYVAL hinst AS HINSTANCE, BYVAL pszName AS PCWSTR, BYVAL lims AS LONG, BYVAL phico AS HICON PTR) AS HRESULT
pLoadIconMetric = DyLibSymbol(pLib, "LoadIconMetric")
IF pLoadIconMetric = NULL THEN EXIT FUNCTION
FUNCTION = pLoadIconMetric(hinst, pszName, lims, phico)
DyLibFree(pLib)
END FUNCTION
' ========================================================================================
' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, _
BYVAL hPrevInstance AS HINSTANCE, _
BYVAL szCmdLine AS ZSTRING PTR, _
BYVAL nCmdShow AS LONG) AS LONG
' // Set process DPI aware
AfxSetProcessDPIAware
DIM pWindow AS CWindow
pWindow.Create(NULL, "mCtrl Split Button", @WndProc)
pWindow.SetClientSize(525, 305)
pWindow.Center
' // Initialize mCtrl control
IF mcButton_Initialize = FALSE THEN EXIT FUNCTION
' // Add controls
pWindow.AddControl("Button", , ID_BUTTON_ICON_1, "", 9, 9, 61, 66, WS_CHILD OR WS_VISIBLE OR WS_TABSTOP OR BS_ICON)
pWindow.AddControl(MC_WC_BUTTONW, , ID_BUTTON_ICON_2, "", 9, 84, 61, 66, WS_CHILD OR WS_VISIBLE OR WS_TABSTOP OR BS_ICON)
pWindow.AddControl("Label", , -1, "On left, you can see two buttons with BS_ICON style. " & _
"The upper one is the standard button (window class 'BUTTON'). If you are running on Windows XP " & _
"and don't have visual styles disabled you can see its style does not match rest of the window.", _
88, 9, 420, 66)
pWindow.AddControl("Label", , -1, "The lower button is mCtrl's MC_WC_BUTTON which provides the look " & _
"and feel consistent with rest of the Windows.", 88, 84, 420, 66)
pWindow.AddControl(MC_WC_BUTTONW, , ID_BUTTON_SPLIT_1, "&Split button", 9, 169, 123, 47, WS_CHILD OR WS_VISIBLE OR WS_TABSTOP OR MC_BS_SPLITBUTTON)
pWindow.AddControl(MC_WC_BUTTONW, , ID_BUTTON_SPLIT_2, "", 9, 225, 123, 66, WS_CHILD OR WS_VISIBLE OR WS_TABSTOP OR BS_ICON OR MC_BS_SPLITBUTTON)
pWindow.AddControl("Label", , -1, "Microsoft introduced split buttons on Windows Vista's comctl32.dll version 6.0. " & _
"Some applications implement their own custom control which provide this funcitonality for compatibility " & _
"with older Windows versions.", 140, 169, 368, 75)
pWindow.AddControl("Label", , -1, "But having each application to reinvent wheel is just bad idea. " & _
"So mCtrl provides a split button for you.", 140, 244, 368, 38)
' // Setup icons for the buttons with BS%ICON style.
DIM hIcon AS HICON
AfxLoadIconMetric(NULL, cast(PCWSTR, IDI_QUESTION), LIM_LARGE, @hIcon)
IF hIcon THEN
SendMessageW(pWindow.ControlHandle(ID_BUTTON_ICON_1), BM_SETIMAGE, IMAGE_ICON, cast(LPARAM, hIcon))
SendMessageW(pWindow.ControlHandle(ID_BUTTON_ICON_2), BM_SETIMAGE, IMAGE_ICON, cast(LPARAM, hIcon))
SendMessageW(pWindow.ControlHandle(ID_BUTTON_SPLIT_2), BM_SETIMAGE, IMAGE_ICON, cast(LPARAM, hIcon))
END IF
FUNCTION = pWindow.DoEvents(nCmdShow)
END FUNCTION
' ========================================================================================
' ========================================================================================
' Window procedure
' ========================================================================================
FUNCTION WndProc (BYVAL hWnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
SELECT CASE uMsg
CASE WM_CREATE
EXIT FUNCTION
CASE WM_COMMAND
SELECT CASE LOWORD(wParam)
CASE IDCANCEL
' // If ESC key pressed, close the application sending an WM_CLOSE message
IF HIWORD(wParam) = BN_CLICKED THEN
SendMessageW hwnd, WM_CLOSE, 0, 0
EXIT FUNCTION
END IF
' // React when user clicks on button (for split buttons, only the
' // main part of the control as drop-down is handled in WM_NOTIFY)
CASE ID_BUTTON_ICON_1
MessageBoxW hwnd, "The upper BS_ICON button has been clicked.", "", MB_OK
CASE ID_BUTTON_ICON_2
MessageBoxW hwnd, "The lower BS_ICON button has been clicked.", "", MB_OK
CASE ID_BUTTON_SPLIT_1
MessageBoxW hwnd, "The text split button has been clicked.", "", MB_OK
CASE ID_BUTTON_SPLIT_2
MessageBoxW hwnd, "The icon split button has been clicked.", "", MB_OK
END SELECT
CASE WM_NOTIFY
DIM nm AS MC_NMBCDROPDOWN PTR = cast(MC_NMBCDROPDOWN PTR, lParam)
IF (nm->hdr.idFrom = ID_BUTTON_SPLIT_1 OR nm->hdr.idFrom = ID_BUTTON_SPLIT_2) AND _
nm->hdr.code = MC_BCN_DROPDOWN THEN
DIM mii AS MENUITEMINFOW
DIM hMenu AS HMENU = CreatePopupMenu
mii.cbSize = sizeof(MENUITEMINFOW)
mii.fMask = MIIM_TYPE
mii.fType = MFT_STRING
mii.dwTypeData = cast(WSTRING PTR, @WSTR("item 1"))
InsertMenuItemW(hMenu, 0, CTRUE, @mii)
mii.dwTypeData = cast(WSTRING PTR, @WSTR("item 2"))
InsertMenuItemW(hMenu, 1, CTRUE, @mii)
ClientToScreen(nm->hdr.hwndFrom, cast(POINT PTR, @nm->rcButton) + 1)
TrackPopupMenu(hMenu, TPM_RIGHTALIGN OR TPM_LEFTBUTTON, _
nm->rcButton.right, nm->rcButton.bottom, 0, hwnd, NULL)
END IF
CASE WM_DESTROY
PostQuitMessage(0)
EXIT FUNCTION
END SELECT
FUNCTION = DefWindowProcW(hWnd, uMsg, wParam, lParam)
END FUNCTION
' ========================================================================================
See in the captures the difference in sharpness at 192 DPI between the CWindow version and the original one.
Updated mCtrl.bi header.
I have been investigating the source code and I think that I can extend the functionality of the tab and html controls.
With the tab control, my idea is to write a class like CTabPage (in CWindow.inc). To make good use of it, you don't have to insert or remove tabs directly, but insert or delete tab pages, that in turn, will insert or remove the associated tab.
Regarding the html control, I think that I can get a pointer to the IOleObject interface from the handle of the window that contains it, and with that pointer I can do wathever I wish.
Excellent.
The problem I brought up earlier with the grid appears(?) to be fixed. I have not done any real testing yet.
James
It was a macro to append and A or an W. I have replaced it with #ifdef UNICODE ... #end if.