PlanetSquires Forums

Please login or register.

Login with username, password and session length
Advanced search  

Author Topic: mCtrl - Split Button example  (Read 1777 times)

Josť Roca

  • Guru Member
  • *****
  • Posts: 3205
mCtrl - Split Button example
« on: June 14, 2016, 02:17:59 PM »

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.

Code: [Select]
' ########################################################################################
' 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.
« Last Edit: June 14, 2016, 05:06:14 PM by Jose Roca »
Logged

Josť Roca

  • Guru Member
  • *****
  • Posts: 3205
Re: mCtrl - Split Button example
« Reply #1 on: June 14, 2016, 04:54:37 PM »

Updated mCtrl.bi header.

Josť Roca

  • Guru Member
  • *****
  • Posts: 3205
Re: mCtrl - Split Button example
« Reply #2 on: June 14, 2016, 06:47:20 PM »

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.

James Fuller

  • Senior Member
  • ***
  • Posts: 283
  • FF3 User
Re: mCtrl - Split Button example
« Reply #3 on: June 14, 2016, 07:35:05 PM »

Excellent.
 The problem I brought up earlier with the grid appears(?) to be fixed. I have not done any real testing yet.

James
Logged

Josť Roca

  • Guru Member
  • *****
  • Posts: 3205
Re: mCtrl - Split Button example
« Reply #4 on: June 14, 2016, 08:22:00 PM »

It was a macro to append and A or an W. I have replaced it with #ifdef UNICODE ... #end if.