PlanetSquires Forums

Support Forums => José Roca Software => Topic started by: José Roca on June 10, 2016, 04:20:13 PM

Title: CWindow RC10
Post by: José Roca on June 10, 2016, 04:20:13 PM
Includes AfxCtl.inc, with wrappers for the Windows Common Controls messages that have no macros in windowsx.bi or commonctrl.bi, and some more. The only missing is the Rich Edit control. Will do later.

The help file documents all the wrappers and also the macros for the common controls in windowsx and commctrl.

It has been an huge task. Hope there aren't too many mistakes.


Title: Re: CWindow RC10
Post by: Paul Squires on June 10, 2016, 07:00:50 PM
Wow! Incredible! The FB version of CWindow has certainly taken shape and is extremely usable. These common wrappers are the icing on the cake.
Title: Re: CWindow RC10
Post by: James Fuller on June 10, 2016, 08:28:06 PM
I concur. Outstanding job.

James

Title: Re: CWindow RC10
Post by: José Roca on June 11, 2016, 11:31:40 AM
An example that demonstrates the use of some of the TreeView wrappers:


' ########################################################################################
' Microsoft Windows
' File: CW_COMMCTRL_TreeView_Layout2.fbtpl
' Contents: Template - CWindow with a TreeView
' Compiler: Free Basic
' 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.
' ########################################################################################

#INCLUDE ONCE "Afx/CWindow.inc"
#INCLUDE ONCE "Afx/AfxCtl.inc"
#INCLUDE ONCE "Afx/CLayout.inc"
USING Afx.CWindowClass
USING Afx.CLayoutClass

#define IDC_TREEVIEW 1001
#define IDC_EXPAND 1002
#define IDC_COLLAPSE 1003
#define IDC_TOGGLE 1004

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)

' ========================================================================================
' Window procedure
' ================================================================e========================
FUNCTION WndProc (BYVAL hWnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   ' // Scaling ratios
   STATIC AS SINGLE rxRatio, ryRatio

   SELECT CASE uMsg

      CASE WM_CREATE
         ' // Get the scaling ratios
         rxRatio = AfxCWindowPtr(lParam)->rxRatio
         ryRatio = AfxCWindowPtr(lParam)->ryRatio
         EXIT FUNCTION

      CASE WM_COMMAND
         SELECT CASE LOWORD(wParam)
            ' // If ESC key pressed, close the application sending an WM_CLOSE message
            CASE IDCANCEL
               IF HIWORD(wParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
            ' // Collapse the root node
            CASE IDC_COLLAPSE
               DIM hTreeView AS HWND = GetDlgItem(hwnd, IDC_TREEVIEW)
               TreeView_Expand(hTreeView, TreeView_GetRoot(hTreeView), TVE_COLLAPSE)
               EXIT FUNCTION
            ' // Expand the root node
            CASE IDC_EXPAND
               DIM hTreeView AS HWND = GetDlgItem(hwnd, IDC_TREEVIEW)
               TreeView_Expand(hTreeView, TreeView_GetRoot(hTreeView), TVE_EXPAND)
               EXIT FUNCTION
            ' // Toggle the root node
            CASE IDC_TOGGLE
               DIM hTreeView AS HWND = GetDlgItem(hwnd, IDC_TREEVIEW)
               TreeView_Expand(hTreeView, TreeView_GetRoot(hTreeView), TVE_TOGGLE)
               EXIT FUNCTION
         END SELECT

      CASE WM_NOTIFY
         DIM ptnmhdr AS NMHDR PTR = CAST(NMHDR PTR, lParam)
         SELECT CASE ptnmhdr->idFrom
            CASE IDC_TREEVIEW
               IF ptnmhdr->code = NM_DBLCLK THEN
                  ' // Retrieve the handle of the TreeView
                  DIM hTreeView AS HWND = GetDlgItem(hwnd, IDC_TREEVIEW)
                  ' // Retrieve the selected item
                  DIM hItem AS HTREEITEM = TreeView_GetSelection(hTreeView)
                  ' // Retrieve the text of the selected item
                  DIM wszText AS WSTRING * 260
                  TreeView_GetItemText(hTreeView, hItem, @wszText, 260)
                  MessageBox hwnd, wszText, "", MB_OK
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE WM_GETMINMAXINFO
         ' // Set the pointer to the address of the MINMAXINFO structure
         DIM ptmmi AS MINMAXINFO PTR = CAST(MINMAXINFO PTR, lParam)
         ' // Set the minimum and maximum sizes that can be produced by dragging the borders of the window
         ptmmi->ptMinTrackSize.x = 350 * rxRatio
         ptmmi->ptMinTrackSize.y = 150 * ryRatio
         EXIT FUNCTION

      CASE WM_SIZE
         ' // Adjusts the controls
         DIM pLayout AS CLayout PTR = CAST(CLayout PTR, GetPropW(hwnd, "CLAYOUTPTR"))
         IF pLayout THEN pLayout->AdjustControls
         EXIT FUNCTION

    CASE WM_DESTROY
         ' // Remove the property
         RemovePropW hwnd, "CLAYOUTPTR"
          ' // End the application
         PostQuitMessage(0)
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to DefWindowProc
   FUNCTION = DefWindowProcW(hWnd, uMsg, wParam, lParam)

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, "CWindow with a TreeView", @WndProc)
   pWindow.ClassStyle = CS_DBLCLKS   ' // Change the window style to avoid flicker
   pWindow.SetClientSize(337, 370)
   pWindow.Center

   ' // Add a TreeView
   DIM hTreeView AS HWND
   hTreeView = pWindow.AddControl("TreeView", , IDC_TREEVIEW, "")
   pWindow.SetWindowPos hTreeView, NULL, 8, 8, 320, 320, SWP_NOZORDER

   ' // Add items to the TreeView
   DIM AS HTREEITEM hRoot, hNode, hItem
   ' // Create the root node
   hRoot = TreeView_AddRootItem(hTreeView, "Root")
   ' // Create a node
   hNode = TreeView_AppendItem(hTreeView, hRoot, "Node 1")
   ' // Insert items in the node
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 1")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 2")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 3")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 4")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 5")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 6")
   ' // Expand the node
   TreeView_Expand(hTreeView, hNode, TVM_EXPAND)
   ' // Create another node
   hNode = TreeView_AppendItem(hTreeView, hRoot, "Node 2")
   ' // Insert items in the node
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 1")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 2")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 3")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 4")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 5")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 6")
   ' // Expand the node
   TreeView_Expand(hTreeView, hNode, TVM_EXPAND)
   ' // Create another node
   hNode = TreeView_AppendItem(hTreeView, hRoot, "Node 3")
   ' // Insert items in the node
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 1")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 2")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 3")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 4")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 5")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 6")
   ' // Expand the node
   TreeView_Expand(hTreeView, hNode, TVM_EXPAND)
   ' // Create another node
   hNode = TreeView_AppendItem(hTreeView, hRoot, "Node 4")
   ' // Insert items in the node
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 1")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 2")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 3")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 4")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 5")
   hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 6")
   ' // Expand the node
   TreeView_Expand(hTreeView, hNode, TVM_EXPAND)

   ' // Expand the root node
   TreeView_Expand(hTreeView, hRoot, TVE_EXPAND)

   pWindow.AddControl("Button", , IDC_EXPAND, "&Expand", 8, 338, 75, 23)
   pWindow.AddControl("Button", , IDC_COLLAPSE, "&Collapse", 90, 338, 75, 23)
   pWindow.AddControl("Button", , IDC_TOGGLE, "&Toggle", 172, 338, 75, 23)

   ' // Add a cancel button
   pWindow.AddControl("Button", , IDCANCEL, "&Cancel", 254, 338, 75, 23)

   ' // Anchor the controls
   DIM pLayout AS CLayout = pWindow.hWindow
   SetPropW pWindow.hWindow, "CLAYOUTPTR", @pLayout
   pLayout.AnchorControl(GetDlgItem(pWindow.hWindow, IDC_TREEVIEW), AFX_ANCHOR_HEIGHT_WIDTH)
   pLayout.AnchorControl(GetDlgItem(pWindow.hWindow, IDC_EXPAND), AFX_ANCHOR_BOTTOM)
   pLayout.AnchorControl(GetDlgItem(pWindow.hWindow, IDC_COLLAPSE), AFX_ANCHOR_BOTTOM)
   pLayout.AnchorControl(GetDlgItem(pWindow.hWindow, IDC_TOGGLE), AFX_ANCHOR_BOTTOM)
   pLayout.AnchorControl(GetDlgItem(pWindow.hWindow, IDCANCEL), AFX_ANCHOR_BOTTOM_RIGHT)

   

   ' // Process Windows messages
   FUNCTION = pWindow.DoEvents(nCmdShow)

END FUNCTION
' ========================================================================================

Title: Re: CWindow RC10
Post by: José Roca on June 11, 2016, 11:35:55 AM
As some like to create the controls in WM_CREATE (à la Petzold), there are two ways to do it with CWindow. In the following example, we get a pointer to the CWindow class calling AfxCWindowPtr(lParam) and using hwnd as the parent instead of pWindow.hWindow or omiting that parameter because CWindow does not know the window handle until WM_CREATE has exited.


' ########################################################################################
' Microsoft Windows
' File: CW_COMMCTRL_TreeView_Layout2.fbtpl
' Contents: Template - CWindow with a TreeView
' Compiler: Free Basic
' 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.
' ########################################################################################

#INCLUDE ONCE "Afx/CWindow.inc"
#INCLUDE ONCE "Afx/AfxCtl.inc"
#INCLUDE ONCE "Afx/CLayout.inc"
USING Afx.CWindowClass
USING Afx.CLayoutClass

#define IDC_TREEVIEW 1001
#define IDC_EXPAND 1002
#define IDC_COLLAPSE 1003
#define IDC_TOGGLE 1004

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)

' ========================================================================================
' Window procedure
' ================================================================e========================
FUNCTION WndProc (BYVAL hWnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   STATIC AS SINGLE rxRatio, ryRatio
   STATIC hTreeView AS HWND

   SELECT CASE uMsg

      CASE WM_CREATE
         ' Get a pointer to the CWindow clas
         DIM pWindow AS CWindow PTR = AfxCWindowPtr(lParam)
         ' // Get the scaling ratios
         rxRatio = pWindow->rxRatio
         ryRatio = pWindow->ryRatio
         ' // Add a TreeView
         ' // Note that we have are using hwnd as the parent instead of pWindow.hWindow
         ' // because the CWindow class does not know the handle of the window until
         ' // WM_CREATE message has exited.
         hTreeView = pWindow->AddControl("TreeView", hwnd, IDC_TREEVIEW, "")
         pWindow->SetWindowPos hTreeView, NULL, 8, 8, 320, 320, SWP_NOZORDER
         ' // Add items to the TreeView
         DIM AS HTREEITEM hRoot, hNode, hItem
         ' // Create the root node
         hRoot = TreeView_AddRootItem(hTreeView, "Root")
         ' // Create a node
         hNode = TreeView_AppendItem(hTreeView, hRoot, "Node 1")
         ' // Insert items in the node
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 1")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 2")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 3")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 4")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 5")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 6")
         ' // Expand the node
         TreeView_Expand(hTreeView, hNode, TVM_EXPAND)
         ' // Create another node
         hNode = TreeView_AppendItem(hTreeView, hRoot, "Node 2")
         ' // Insert items in the node
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 1")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 2")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 3")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 4")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 5")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 6")
         ' // Expand the node
         TreeView_Expand(hTreeView, hNode, TVM_EXPAND)
         ' // Create another node
         hNode = TreeView_AppendItem(hTreeView, hRoot, "Node 3")
         ' // Insert items in the node
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 1")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 2")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 3")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 4")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 5")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 6")
         ' // Expand the node
         TreeView_Expand(hTreeView, hNode, TVM_EXPAND)
         ' // Create another node
         hNode = TreeView_AppendItem(hTreeView, hRoot, "Node 4")
         ' // Insert items in the node
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 1")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 2")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 3")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 4")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 5")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 6")
         ' // Expand the node
         TreeView_Expand(hTreeView, hNode, TVM_EXPAND)
         ' // Expand the root node
         TreeView_Expand(hTreeView, hRoot, TVE_EXPAND)
         ' // Add the buttons
         pWindow->AddControl("Button", hwnd, IDC_EXPAND, "&Expand", 8, 338, 75, 23)
         pWindow->AddControl("Button", hwnd, IDC_COLLAPSE, "&Collapse", 90, 338, 75, 23)
         pWindow->AddControl("Button", hwnd, IDC_TOGGLE, "&Toggle", 172, 338, 75, 23)
         pWindow->AddControl("Button", hwnd, IDCANCEL, "&Cancel", 254, 338, 75, 23)
         EXIT FUNCTION

      CASE WM_COMMAND
         SELECT CASE LOWORD(wParam)
            ' // If ESC key pressed, close the application sending an WM_CLOSE message
            CASE IDCANCEL
               IF HIWORD(wParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
            ' // Collapse the root node
            CASE IDC_COLLAPSE
               TreeView_Expand(hTreeView, TreeView_GetRoot(hTreeView), TVE_COLLAPSE)
               EXIT FUNCTION
            ' // Expand the root node
            CASE IDC_EXPAND
               TreeView_Expand(hTreeView, TreeView_GetRoot(hTreeView), TVE_EXPAND)
               EXIT FUNCTION
            ' // Toggle the root node
            CASE IDC_TOGGLE
               TreeView_Expand(hTreeView, TreeView_GetRoot(hTreeView), TVE_TOGGLE)
               EXIT FUNCTION
         END SELECT

      CASE WM_NOTIFY
         DIM ptnmhdr AS NMHDR PTR = CAST(NMHDR PTR, lParam)
         SELECT CASE ptnmhdr->idFrom
            CASE IDC_TREEVIEW
               IF ptnmhdr->code = NM_DBLCLK THEN
                  ' // Retrieve the selected item
                  DIM hItem AS HTREEITEM = TreeView_GetSelection(hTreeView)
                  ' // Retrieve the text of the selected item
                  DIM wszText AS WSTRING * 260
                  TreeView_GetItemText(hTreeView, hItem, @wszText, 260)
                  MessageBox hwnd, wszText, "", MB_OK
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE WM_GETMINMAXINFO
         ' // Set the pointer to the address of the MINMAXINFO structure
         DIM ptmmi AS MINMAXINFO PTR = CAST(MINMAXINFO PTR, lParam)
         ' // Set the minimum and maximum sizes that can be produced by dragging the borders of the window
         ptmmi->ptMinTrackSize.x = 350 * rxRatio
         ptmmi->ptMinTrackSize.y = 150 * ryRatio
         EXIT FUNCTION

      CASE WM_SIZE
         ' // Adjusts the controls
         DIM pLayout AS CLayout PTR = CAST(CLayout PTR, GetPropW(hwnd, "CLAYOUTPTR"))
         IF pLayout THEN pLayout->AdjustControls
         EXIT FUNCTION

    CASE WM_DESTROY
         ' // Remove the property
         RemovePropW hwnd, "CLAYOUTPTR"
          ' // End the application
         PostQuitMessage(0)
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to DefWindowProc
   FUNCTION = DefWindowProcW(hWnd, uMsg, wParam, lParam)

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, "CWindow with a TreeView", @WndProc)
   pWindow.ClassStyle = CS_DBLCLKS   ' // Change the window style to avoid flicker
   pWindow.SetClientSize(337, 370)
   pWindow.Center


   ' // Anchor the controls
   DIM pLayout AS CLayout = pWindow.hWindow
   SetPropW pWindow.hWindow, "CLAYOUTPTR", @pLayout
   pLayout.AnchorControl(GetDlgItem(pWindow.hWindow, IDC_TREEVIEW), AFX_ANCHOR_HEIGHT_WIDTH)
   pLayout.AnchorControl(GetDlgItem(pWindow.hWindow, IDC_EXPAND), AFX_ANCHOR_BOTTOM)
   pLayout.AnchorControl(GetDlgItem(pWindow.hWindow, IDC_COLLAPSE), AFX_ANCHOR_BOTTOM)
   pLayout.AnchorControl(GetDlgItem(pWindow.hWindow, IDC_TOGGLE), AFX_ANCHOR_BOTTOM)
   pLayout.AnchorControl(GetDlgItem(pWindow.hWindow, IDCANCEL), AFX_ANCHOR_BOTTOM_RIGHT)



   ' // Process Windows messages
   FUNCTION = pWindow.DoEvents(nCmdShow)

END FUNCTION
' ========================================================================================

Title: Re: CWindow RC10
Post by: José Roca on June 11, 2016, 11:39:09 AM
The second way is to let to know CWindow the handle of the window calling pWindow->hWindow = hwnd. Adter that, we can use both hTreeView = pWindow->AddControl("TreeView", pWindow->hWIndow, IDC_TREEVIEW, "") or hTreeView = pWindow->AddControl("TreeView", , IDC_TREEVIEW, "").


' ########################################################################################
' Microsoft Windows
' File: CW_COMMCTRL_TreeView_Layout2.fbtpl
' Contents: Template - CWindow with a TreeView
' Compiler: Free Basic
' 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.
' ########################################################################################

#INCLUDE ONCE "Afx/CWindow.inc"
#INCLUDE ONCE "Afx/AfxCtl.inc"
#INCLUDE ONCE "Afx/CLayout.inc"
USING Afx.CWindowClass
USING Afx.CLayoutClass

#define IDC_TREEVIEW 1001
#define IDC_EXPAND 1002
#define IDC_COLLAPSE 1003
#define IDC_TOGGLE 1004

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)

' ========================================================================================
' Window procedure
' ================================================================e========================
FUNCTION WndProc (BYVAL hWnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   STATIC AS SINGLE rxRatio, ryRatio
   DIM hTreeView AS HWND

   SELECT CASE uMsg

      CASE WM_CREATE
         ' // Get a pointer to the CWindow clas
         DIM pWindow AS CWindow PTR
         pWindow = AfxCWindowPtr(lParam)
         ' // Get the scaling ratios
         rxRatio = pWindow->rxRatio
         ryRatio = pWindow->ryRatio
         ' // Set the window handle
         pWindow->hWindow = hwnd
         ' // Add a TreeView
         hTreeView = pWindow->AddControl("TreeView", , IDC_TREEVIEW, "")
         pWindow->SetWindowPos hTreeView, NULL, 8, 8, 320, 320, SWP_NOZORDER
         ' // Add items to the TreeView
         DIM AS HTREEITEM hRoot, hNode, hItem
         ' // Create the root node
         hRoot = TreeView_AddRootItem(hTreeView, "Root")
         ' // Create a node
         hNode = TreeView_AppendItem(hTreeView, hRoot, "Node 1")
         ' // Insert items in the node
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 1")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 2")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 3")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 4")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 5")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 1 Item 6")
         ' // Expand the node
         TreeView_Expand(hTreeView, hNode, TVM_EXPAND)
         ' // Create another node
         hNode = TreeView_AppendItem(hTreeView, hRoot, "Node 2")
         ' // Insert items in the node
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 1")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 2")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 3")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 4")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 5")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 2 Item 6")
         ' // Expand the node
         TreeView_Expand(hTreeView, hNode, TVM_EXPAND)
         ' // Create another node
         hNode = TreeView_AppendItem(hTreeView, hRoot, "Node 3")
         ' // Insert items in the node
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 1")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 2")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 3")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 4")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 5")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 3 Item 6")
         ' // Expand the node
         TreeView_Expand(hTreeView, hNode, TVM_EXPAND)
         ' // Create another node
         hNode = TreeView_AppendItem(hTreeView, hRoot, "Node 4")
         ' // Insert items in the node
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 1")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 2")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 3")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 4")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 5")
         hItem = TreeView_AppendItem(hTreeView, hNode, "Node 4 Item 6")
         ' // Expand the node
         TreeView_Expand(hTreeView, hNode, TVM_EXPAND)
         ' // Expand the root node
         TreeView_Expand(hTreeView, hRoot, TVE_EXPAND)
         ' // Add the buttons
         pWindow->AddControl("Button", , IDC_EXPAND, "&Expand", 8, 338, 75, 23)
         pWindow->AddControl("Button", , IDC_COLLAPSE, "&Collapse", 90, 338, 75, 23)
         pWindow->AddControl("Button", , IDC_TOGGLE, "&Toggle", 172, 338, 75, 23)
         pWindow->AddControl("Button", , IDCANCEL, "&Cancel", 254, 338, 75, 23)
         EXIT FUNCTION

      CASE WM_COMMAND
         SELECT CASE LOWORD(wParam)
            ' // If ESC key pressed, close the application sending an WM_CLOSE message
            CASE IDCANCEL
               IF HIWORD(wParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
            ' // Collapse the root node
            CASE IDC_COLLAPSE
               TreeView_Expand(hTreeView, TreeView_GetRoot(hTreeView), TVE_COLLAPSE)
               EXIT FUNCTION
            ' // Expand the root node
            CASE IDC_EXPAND
               TreeView_Expand(hTreeView, TreeView_GetRoot(hTreeView), TVE_EXPAND)
               EXIT FUNCTION
            ' // Toggle the root node
            CASE IDC_TOGGLE
               TreeView_Expand(hTreeView, TreeView_GetRoot(hTreeView), TVE_TOGGLE)
               EXIT FUNCTION
         END SELECT

      CASE WM_NOTIFY
         DIM ptnmhdr AS NMHDR PTR = CAST(NMHDR PTR, lParam)
         SELECT CASE ptnmhdr->idFrom
            CASE IDC_TREEVIEW
               IF ptnmhdr->code = NM_DBLCLK THEN
                  ' // Retrieve the selected item
                  DIM hItem AS HTREEITEM = TreeView_GetSelection(hTreeView)
                  ' // Retrieve the text of the selected item
                  DIM wszText AS WSTRING * 260
                  TreeView_GetItemText(hTreeView, hItem, @wszText, 260)
                  MessageBox hwnd, wszText, "", MB_OK
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE WM_GETMINMAXINFO
         ' // Set the pointer to the address of the MINMAXINFO structure
         DIM ptmmi AS MINMAXINFO PTR = CAST(MINMAXINFO PTR, lParam)
         ' // Set the minimum and maximum sizes that can be produced by dragging the borders of the window
         ptmmi->ptMinTrackSize.x = 350 * rxRatio
         ptmmi->ptMinTrackSize.y = 150 * ryRatio
         EXIT FUNCTION

      CASE WM_SIZE
         ' // Adjusts the controls
         DIM pLayout AS CLayout PTR = CAST(CLayout PTR, GetPropW(hwnd, "CLAYOUTPTR"))
         IF pLayout THEN pLayout->AdjustControls
         EXIT FUNCTION

    CASE WM_DESTROY
         ' // Remove the property
         RemovePropW hwnd, "CLAYOUTPTR"
          ' // End the application
         PostQuitMessage(0)
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to DefWindowProc
   FUNCTION = DefWindowProcW(hWnd, uMsg, wParam, lParam)

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, "CWindow with a TreeView", @WndProc)
   pWindow.ClassStyle = CS_DBLCLKS   ' // Change the window style to avoid flicker
   pWindow.SetClientSize(337, 370)
   pWindow.Center


   ' // Anchor the controls
   DIM pLayout AS CLayout = pWindow.hWindow
   SetPropW pWindow.hWindow, "CLAYOUTPTR", @pLayout
   pLayout.AnchorControl(GetDlgItem(pWindow.hWindow, IDC_TREEVIEW), AFX_ANCHOR_HEIGHT_WIDTH)
   pLayout.AnchorControl(GetDlgItem(pWindow.hWindow, IDC_EXPAND), AFX_ANCHOR_BOTTOM)
   pLayout.AnchorControl(GetDlgItem(pWindow.hWindow, IDC_COLLAPSE), AFX_ANCHOR_BOTTOM)
   pLayout.AnchorControl(GetDlgItem(pWindow.hWindow, IDC_TOGGLE), AFX_ANCHOR_BOTTOM)
   pLayout.AnchorControl(GetDlgItem(pWindow.hWindow, IDCANCEL), AFX_ANCHOR_BOTTOM_RIGHT)



   ' // Process Windows messages
   FUNCTION = pWindow.DoEvents(nCmdShow)

END FUNCTION
' ========================================================================================

Title: Re: CWindow RC10
Post by: José Roca on June 11, 2016, 11:46:27 AM
The next version of CWindow will feature the ControlHandle method, so besides GetDlgItem(pWindow.hWindow, IDC_TREEVIEW) we could also use pWindow.ControlHandle(IDC_TREEVIEW). Not a big improvement, but maybe beginners will find it easier to remember and understand than GetDlgItem.
Title: Re: CWindow RC10
Post by: José Roca on June 12, 2016, 05:26:15 AM
For one of the examples below I had the need of retrieve the path of a system dll, so I have incoporated this wrapper function to AfxWin.inc.


' ========================================================================================
' Retrieves the fully qualified path of the specified system DLL.
' ========================================================================================
PRIVATE FUNCTION AfxGetSystemDllPath (BYVAL pwszDllName AS WSTRING PTR, BYVAL pwszDllPath AS WSTRING PTR, BYVAL cchCount AS DWORD) AS LONG
   IF pwszDllName = NULL OR pwszDllPath = NULL OR cchCount = 0 THEN EXIT FUNCTION
   DIM hLib AS HMODULE
   hLib = LoadLibraryW(pwszDllName)
   IF hLib THEN
      FUNCTION = GetModuleFileNameW(hLib, pwszDllPath, cchCount)
      FreeLibrary hLib
   END IF
END FUNCTION
' ========================================================================================

Title: Re: CWindow RC10
Post by: José Roca on June 12, 2016, 05:36:52 AM
Pick Icon File Dialog

The PickIconFileDialog allows to add an icon-selection dialog box to your applications.

The following example demonstrates how to use it to display the icons from the resource file of shell32.dll. If you select an icon, the application extraxts it and sets it as the application icon.


' ########################################################################################
' Microsoft Windows
' File: CW_COMMCTRL_PickIconDlg.fbtpl
' Contents: Demonstrates the use of the Pick icon dialog.
' 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.
' ########################################################################################

#INCLUDE ONCE "Afx/CWindow.inc"
#INCLUDE ONCE "win/shlobj.bi"
USING Afx.CWindowClass

CONST IDC_PICKDLG = 1001   ' // Pick icon dialog identifier

' // Forward declaration
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)

' ========================================================================================
' 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, "CWindow with a button", @WndProc)
   pWindow.SetClientSize(500, 320)
   pWindow.Center

   ' // Add buttons without position or size (it will be resized in the WM_SIZE message).
   pWindow.AddControl("Button", , IDC_PICKDLG, "&Pick")
   pWindow.AddControl("Button", , IDCANCEL, "&Close")


   ' // Process Windows messages
   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

   STATIC wszIconPath AS WSTRING * MAX_PATH   ' // Path of the resource file containing the icons
   STATIC nIconIndex AS LONG                  ' // Icon index
   STATIC hIcon AS HICON                      ' // Icon handle

   SELECT CASE uMsg

      CASE WM_COMMAND
         ' // If ESC key pressed, close the application sending an WM_CLOSE message
         SELECT CASE LOWORD(wParam)
            CASE IDCANCEL
               IF HIWORD(wParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
            ' // Launch the Pick icon dialog
            CASE IDC_PICKDLG
               IF HIWORD(wParam) = BN_CLICKED THEN
                  IF LEN(wszIconPath) = 0 THEN AfxGetSystemDllPath("Shell32.dll", wszIconPath, MAX_PATH)
                  IF LEN(wszIconPath) = 0 THEN EXIT FUNCTION
                  ' // Activate the Pick Icon Common Dialog Box
                  DIM hr AS LONG = PickIconDlg(0, wszIconPath, SIZEOF(wszIconPath), @nIconIndex)
                  ' // If an icon has been selected...
                  IF hr = 1 THEN
                     ' // Destroy previously loaded icon, if any
                     IF hIcon THEN DestroyIcon(hIcon)
                     ' // Get the handle of the new selected icon
                     hIcon = ExtractIconW(GetModuleHandle(NULL), wszIconPath, nIconIndex)
                     ' // Replace the application icons
                     IF hIcon THEN
                        SendMessageW(hwnd, WM_SETICON, ICON_SMALL, cast(LPARAM, hIcon))
                        SendMessageW(hwnd, WM_SETICON, ICON_BIG, cast(LPARAM, hIcon))
                     END IF
                  END IF
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE WM_SIZE
         IF wParam <> SIZE_MINIMIZED THEN
            ' // Resize the buttons
            DIM pWindow AS CWindow PTR = AfxCWindowPtr(hwnd)
            IF pWindow THEN pWindow->MoveWindow GetDlgItem(hwnd, IDC_PICKDLG), pWindow->ClientWidth - 230, pWindow->ClientHeight - 50, 75, 23, CTRUE
            IF pWindow THEN pWindow->MoveWindow GetDlgItem(hwnd, IDCANCEL), pWindow->ClientWidth - 120, pWindow->ClientHeight - 50, 75, 23, CTRUE
         END IF

    CASE WM_DESTROY
         ' // Destroy the icon
         IF hIcon THEN DestroyIcon(hIcon)
          ' // End the application sending a WM_QUIT message
         PostQuitMessage(0)
         EXIT FUNCTION

   END SELECT

   ' // Process Windows messages
   FUNCTION = DefWindowProcW(hWnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================


Title: Re: CWindow RC10
Post by: José Roca on June 12, 2016, 05:39:30 AM
The following example demonstrates how to use the pick icon dialog to display the icons from our own resource file. The attached file contains the source code and the icons.


' ########################################################################################
' Microsoft Windows
' File: CW_COMMCTRL_PickIconDlg.fbtpl
' Contents: Demonstrates the use of the Pick icon dialog.
' 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.
' ########################################################################################

#INCLUDE ONCE "Afx/CWindow.inc"
#INCLUDE ONCE "win/shlobj.bi"
USING Afx.CWindowClass
' $FB_RESPATH = "PickIconDialog.rc"

CONST IDC_PICKDLG = 1001   ' // Pick icon dialog identifier

' // Forward declaration
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)

' ========================================================================================
' 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, "CWindow with a button", @WndProc)
   pWindow.SetClientSize(500, 320)
   pWindow.Center

   ' // Add buttons without position or size (it will be resized in the WM_SIZE message).
   pWindow.AddControl("Button", , IDC_PICKDLG, "&Pick")
   pWindow.AddControl("Button", , IDCANCEL, "&Close")


   ' // Process Windows messages
   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

   STATIC wszIconPath AS WSTRING * MAX_PATH   ' // Path of the resource file containing the icons
   STATIC nIconIndex AS LONG                  ' // Icon index
   STATIC hIcon AS HICON                      ' // Icon handle

   SELECT CASE uMsg

      CASE WM_COMMAND
         ' // If ESC key pressed, close the application sending an WM_CLOSE message
         SELECT CASE LOWORD(wParam)
            CASE IDCANCEL
               IF HIWORD(wParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
            ' // Launch the Pick icon dialog
            CASE IDC_PICKDLG
               IF HIWORD(wParam) = BN_CLICKED THEN
                  IF LEN(wszIconPath) = 0 THEN
                     ' // Get the full path of our executable
                     GetModuleFileNameW(NULL, wszIconPath, MAX_PATH)
                  END IF
                  ' // Activate the Pick Icon Common Dialog Box
                  DIM hr AS LONG = PickIconDlg(0, wszIconPath, SIZEOF(wszIconPath), @nIconIndex)
                  ' // If an icon has been selected...
                  IF hr = 1 THEN
                     ' // Destroy previously loaded icon, if any
                     IF hIcon THEN DestroyIcon(hIcon)
                     ' // Get the handle of the new selected icon
                     hIcon = ExtractIconW(GetModuleHandle(NULL), wszIconPath, nIconIndex)
                     ' // Replace the application icons
                     IF hIcon THEN
                        SendMessageW(hwnd, WM_SETICON, ICON_SMALL, cast(LPARAM, hIcon))
                        SendMessageW(hwnd, WM_SETICON, ICON_BIG, cast(LPARAM, hIcon))
                     END IF
                  END IF
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE WM_SIZE
         IF wParam <> SIZE_MINIMIZED THEN
            ' // Resize the buttons
            DIM pWindow AS CWindow PTR = AfxCWindowPtr(hwnd)
            IF pWindow THEN pWindow->MoveWindow GetDlgItem(hwnd, IDC_PICKDLG), pWindow->ClientWidth - 230, pWindow->ClientHeight - 50, 75, 23, CTRUE
            IF pWindow THEN pWindow->MoveWindow GetDlgItem(hwnd, IDCANCEL), pWindow->ClientWidth - 120, pWindow->ClientHeight - 50, 75, 23, CTRUE
         END IF

    CASE WM_DESTROY
         ' // Destroy the icon
         IF hIcon THEN DestroyIcon(hIcon)
          ' // End the application sending a WM_QUIT message
         PostQuitMessage(0)
         EXIT FUNCTION

   END SELECT

   ' // Process Windows messages
   FUNCTION = DefWindowProcW(hWnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================

Title: Re: CWindow RC10
Post by: Paul Squires on June 12, 2016, 09:20:50 PM
Hi Jose,

I see that you are #Include the windowsx.bi file when you use AfxCtl.inc. The windowsx.bi file is not translated correctly in the latest FB distribution. Maybe you should code without using it?

#include once "win/windowsx.bi"

I made a cleaned/fixed up version of windowsx.bi and I manually include it my code (well, in WinFBE that is what I am doing). Of course using the windowsx.bi and my windowsxx.bi files together cause duplicate definition errors. So, at this time whenever I include your AfxWin.inc include, i get duplicate errors because of these two lines at the end of the file:

' // Other include files - Must go here for a matter of forward references
'#INCLUDE ONCE "Afx/AfxMenu.inc"
'#INCLUDE ONCE "Afx/AfxCtl.inc"

AfxCtl.inc includes windowsx.bi

Title: Re: CWindow RC10
Post by: James Fuller on June 12, 2016, 09:27:09 PM
Paul,
  I just replaced the original with yours from your Fb Forum Post.
Is that one up to date?

James
Title: Re: CWindow RC10
Post by: Paul Squires on June 12, 2016, 09:28:45 PM
Yes, that one is up to date.
Title: Re: CWindow RC10
Post by: José Roca on June 13, 2016, 01:49:56 AM
Quote
' // Other include files - Must go here for a matter of forward references
'#INCLUDE ONCE "Afx/AfxMenu.inc"
'#INCLUDE ONCE "Afx/AfxCtl.inc"

Remove them. I will add them to my code when needed.

Quote
AfxCtl.inc includes windowsx.bi

Indeed. In AfxCtl.inc I only have added wrappers for the messages that are not covered by windowsx.bi and commctrl.bi. AFAIK the only problem are the message crackers, that I don't use. If I change the name to windowsxx.bi, then the code will fail if somebody that does not have your modified file tries to compile it. Maybe you should replace windows.bi with your include instead of using another name.
Title: Re: CWindow RC10
Post by: James Fuller on June 16, 2016, 12:37:03 PM
Jose,
  I am exploring CBStr and noticed there is not Len(gth) PROPERTY?

James
Title: Re: CWindow RC10
Post by: José Roca on June 16, 2016, 12:47:18 PM
Don't know which version are you using. There is not a length property, but a LEN operator.



' ========================================================================================
' Returns the length of the BSTR in characters
' ========================================================================================
OPERATOR Len (BYREF pCBStr AS CBStr) AS INTEGER
   OPERATOR = SysStringLen(pCBStr.Handle)
END OPERATOR
' ========================================================================================


Usage:


DIM cbs AS CBStr = "test string"
print len(cbs)

Title: Re: CWindow RC10
Post by: James Fuller on June 16, 2016, 01:35:02 PM
Jose,
  I don't see it in CBStr.inc in RC10?

James
Title: Re: CWindow RC10
Post by: José Roca on June 16, 2016, 01:38:24 PM
It is at the end of the file.
Title: Re: CWindow RC10
Post by: James Fuller on June 16, 2016, 01:52:09 PM
Duh...
I'm getting too old for this :)
I added PROPERTY Length any way!!!!
James
Title: Re: CWindow RC10
Post by: José Roca on June 16, 2016, 02:12:30 PM
You need to increase the DPI to get bigger fonts :)
Title: Re: CWindow RC10
Post by: James Fuller on June 20, 2016, 03:17:30 PM
Jose,
  Why do you default to a sizable window with CWindow?

James
Title: Re: CWindow RC10
Post by: José Roca on June 20, 2016, 04:23:10 PM
Just a matter of preference.
Title: Re: CWindow RC10
Post by: James Fuller on June 20, 2016, 05:27:21 PM
Quote from: Jose Roca on June 20, 2016, 04:23:10 PM
Just a matter of preference.
Jose,
  I question it because very seldom have I seen you use layout code with any of your examples.
It would stand to reason (by me anyway) that the window would/should not be sizable unless layout code is used.
And yes I know I can .... but I'm lazy and I want it to be the default :)
James


Title: Re: CWindow RC10
Post by: José Roca on June 20, 2016, 06:14:02 PM
> I question it because very seldom have I seen you use layout code with any of your examples.

These are examples to demonstrate how to create the controls. It doesn't matter if they are resizable or not.

I'm tired of seeing fixed size popup dialogs whose bottom goes outside of my monitor. I want them to be resizable and scrollable. Check if the height of your dialog would be greater than the height of the monitor and adjust it and make the contents scrollable.

I fyou want to code as you did more than ten years ago, it's your choice.

Title: Re: CWindow RC10
Post by: James Fuller on June 20, 2016, 06:47:50 PM
Jose,
  I understand what your saying but I am using YOUR DPI aware CWindow so hopefully these issues will not surface. Not all windows warrant a full control layout.
How about checking for a CW_DEFAULT_STYLE #define and use that if it is defined?

James
Title: Re: CWindow RC10
Post by: José Roca on June 20, 2016, 07:47:11 PM
If you want to make it not resizable use


   pWindow.Create(NULL, "CWindow with a button", @WndProc)
   AfxRemoveWindowStyle(pWindow.hWindow, WS_THICKFRAME)

Title: Re: CWindow RC10
Post by: José Roca on June 21, 2016, 02:08:58 AM
I have been working in a class, CScrollWindow, to make windows scrollable. Tomorrow I will do more tests.

The idea is:

1. Create our window.

2. Set the needed client size to fit all the controls.

3. When the program starts, check the size of the working area.

4. If our window fits in the working area, do nothing.

5. If it is bigger, create an instance of the class passing the handle of our window.

6. Shrink the size of the window to not exceed the size of the working area.

Et voilà, the window will be scrollable. No more Ok, Apply or Cancel buttons unclickable because they're outside the working area.
Title: Re: CWindow RC10
Post by: James Fuller on June 21, 2016, 07:05:23 AM
Quote from: Jose Roca on June 20, 2016, 07:47:11 PM
If you want to make it not resizable use


   pWindow.Create(NULL, "CWindow with a button", @WndProc)
   AfxRemoveWindowStyle(pWindow.hWindow, WS_THICKFRAME)


That will work just fine. Thank You.

Edit: Woops still has a max button. This works"

AfxRemoveWindowStyle(pWindow.hWindow, WS_THICKFRAME OR WS_MAXIMIZEBOX)


James
Title: Re: CWindow RC10
Post by: José Roca on June 21, 2016, 04:58:20 PM
A new class for our framework. SCrollWindow allows to make a window or popup dialog scrollable.

A littlt test:


' ########################################################################################
' Microsoft Windows
' File: CW_ScrollWindow.fbtpl
' Contents: Scrollable window
' Compiler: Free Basic
' 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
#INCLUDE ONCE "Afx/CWindow.inc"
#INCLUDE ONCE "Afx/AfxCtl.inc"
#INCLUDE ONCE "Afx/CScrollWindow.inc"
USING Afx.CWindowClass

#define IDC_LISTBOX 1001

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)

DECLARE FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

' ========================================================================================
' 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
   DIM hwndMain AS HWND = pWindow.Create(NULL, "Scrollable window", @WndProc)
   pWindow.ClassStyle = CS_DBLCLKS   ' // Change the window style to avoid flicker
   ' // Set a client size big enough to display all the controls
   pWindow.SetClientSize(320, 335)

   ' // Add a listbox
   DIM hListBox AS HWND
   hListBox = pWindow.AddControl("ListBox", , IDC_LISTBOX)
   pWindow.SetWindowPos hListBox, NULL, 8, 8, 300, 280, SWP_NOZORDER

   ' // Fill the list box
   DIM i AS LONG, wszText AS WSTRING * 260
   FOR i = 1 TO 50
      wszText = "Item " & RIGHT("00" & STR(i), 2)
      ListBox_AddString(hListBox, @wszText)
   NEXT
   ' // Select the first item
   ListBox_SetCursel(hListBox, 0)

   ' // Add a cancel button
   pWindow.AddControl("Button", , IDCANCEL, "&Cancel", 233, 298, 75, 23)

   ' // Create an instance of the CScrollWindow class and attach the main window to it
   DIM pScrollWindow AS CScrollWindow = hwndMain
   SetPropW hwndMain,"CSCROLLWINDOWPTR", @pScrollWindow
   ' // Shrink the client size
   pWindow.SetClientSize(250, 260)
   ' // Center the window
   pWindow.Center

   

   ' // Message pump
   FUNCTION = pWindow.DoEvents(nCmdShow)

END FUNCTION
' ========================================================================================

' ========================================================================================
' Window procedure
' ================================================================e========================
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_COMMAND
         SELECT CASE LOWORD(wParam)
            ' // If ESC key pressed, close the application sending an WM_CLOSE message
            CASE IDCANCEL
               IF HIWORD(wParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF

         CASE IDC_LISTBOX
            SELECT CASE HIWORD(wParam)
               CASE LBN_DBLCLK
                  ' // Get the handle of the Listbox
                  DIM hListBox AS HWND = GetDlgItem(hwnd, IDC_LISTBOX)
                  ' // Get the current selection
                  DIM curSel AS LONG = ListBox_GetCursel(hListBox)
                  ' // Get the length of the ListBox item text
                  DIM nLen AS LONG = ListBox_GetTextLen(hListBox, curSel)
                  ' // Allocate memory for the buffer
                  DIM pwszText AS WSTRING PTR = CAllocate(nLen + 1, 2)
                  ' // Get the text and display it
                  ListBox_GetText(hListBox, curSel, pwszText)
                  MessageBoxW(hwnd, pwszText, "ListBox test", MB_OK)
                  ' // Deallocate the memory used by the buffer
                  DeAllocate pwszText
                  pwszText = NULL
                  EXIT FUNCTION
            END SELECT

         END SELECT

      CASE WM_SIZE
         DIM pScrollWindow AS CScrollWindow PTR = CAST(CScrollWindow PTR, GetPropW(hwnd, "CSCROLLWINDOWPTR"))
         IF pScrollWindow THEN pScrollWindow->OnSize(wParam, lParam)
         EXIT FUNCTION

      CASE WM_VSCROLL
         DIM pScrollWindow AS CScrollWindow PTR = CAST(CScrollWindow PTR, GetPropW(hwnd, "CSCROLLWINDOWPTR"))
         IF pScrollWindow THEN pScrollWindow->OnVScroll(wParam, lParam)
         EXIT FUNCTION

      CASE WM_HSCROLL
         DIM pScrollWindow AS CScrollWindow PTR = CAST(CScrollWindow PTR, GetPropW(hwnd, "CSCROLLWINDOWPTR"))
         IF pScrollWindow THEN pScrollWindow->OnHScroll(wParam, lParam)
         EXIT FUNCTION

      CASE WM_DESTROY
         ' // Remove the property
         RemovePropW hwnd,"CSCROLLWINDOWPTR"
         ' // End the application
         PostQuitMessage(0)
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to DefWindowProc
   FUNCTION = DefWindowProcW(hWnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================

Title: Re: CWindow RC10
Post by: José Roca on June 21, 2016, 05:07:03 PM
Its main use could be to make sure that our window or dialog will fit in the dimensions of the user's monitor.

Often, we need to make dialogs with many options, using all the available height. But because monitors have many different sizes and resolutions, and also the user could be using a high dpi setting, we risk that part of it becomes unreachable to the user.

ScrollWindow allows us to make a window or dialog scrollable easily. At runtime, we can check if the size of our dialog will exceed the size of the user monitor and make the window scrollable by adjusting the size of the window or dialog to fit the dimensions of the working area of the monitor.
Title: Re: CWindow RC10
Post by: Paul Squires on June 21, 2016, 05:40:26 PM
This is such a great idea. Many times I have been asked how to scroll regular forms/windows. It is great that now there is a class for this and also a class for automatic resizing and repositioning of forms and controls. The framework is really growing into a strong toolbox.
Title: Re: CWindow RC10
Post by: José Roca on June 21, 2016, 05:55:58 PM
Quote from: James Fuller on June 21, 2016, 07:05:23 AM
Quote from: Jose Roca on June 20, 2016, 07:47:11 PM
If you want to make it not resizable use


   pWindow.Create(NULL, "CWindow with a button", @WndProc)
   AfxRemoveWindowStyle(pWindow.hWindow, WS_THICKFRAME)


That will work just fine. Thank You.

Edit: Woops still has a max button. This works"

AfxRemoveWindowStyle(pWindow.hWindow, WS_THICKFRAME OR WS_MAXIMIZEBOX)


James


With the next version of CWindow you can do:

pWindow.ClassStyle = <styles>

e.g.

pWindow.WindowStyle = WS_VISIBLE OR WS_CAPTION OR WS_POPUPWINDOW

There is also a property to set the extended styles.
Title: Re: CWindow RC10
Post by: José Roca on June 21, 2016, 08:16:25 PM
Quote from: TechSupport on June 21, 2016, 05:40:26 PM
This is such a great idea. Many times I have been asked how to scroll regular forms/windows. It is great that now there is a class for this and also a class for automatic resizing and repositioning of forms and controls. The framework is really growing into a strong toolbox.

These are the kind of things that I no longer do for PB because PBer's don't use it. I'm so bored of only seeing DDT code, that I only read a few posts.

One good thing is that as it is standalone class, if someone can do it better he simply has to write his own class and offer it as an alternative.
Title: Re: CWindow RC10
Post by: José Roca on June 21, 2016, 10:02:53 PM
Now that I have the scroll class working well, I will modify the CWindow and CTabPage classes to allow to store the pointer to the scroll class to delete it when the window or the tab page is destroyed. It will also allow to get a pointer to it calling a method instead of having to use a SetPropW / GetPropW / RemovePropW.

In this post, an user asked you how to create a scrollable tab page: http://www.planetsquires.com/protect/forum/index.php?topic=3795.msg27648#msg27648

With CWindow and CScrollWindow it is a piece of cake:

The "trick" is to get the client size of the tab page, make it larger, attach it to an instance of CScrollWindow, and restore the original client size.


   ' ************************************************************************
   ' // Make the first tab page scrollable
   ' // TODO: Modify the CTabPage class to set the pointer to CScrollWindow
   ' // to delete this class when the tab page is destroyed.
   ' ************************************************************************
   ' // Get the client size of the first page and make it greater
   DIM nWidth AS LONG = pTabPage1->ClientWidth
   DIM nHeight AS LONG = pTabPage1->ClientHeight
   pTabPage1->SetClientSize(nWidth + 150, nHeight + 150)
   ' // Create an instance of the CScrollWindow class and attach the window handle to it
   DIM pScrollWindow AS CScrollWindow = pTabPage1->hTabPage
   SetPropW pTabPage1->hTabPage,"CSCROLLWINDOWPTR", @pScrollWindow
   ' // Shrink the client size back to original
   pTabPage1->SetClientSize(nWidth, nHeight)


CScrollWindow will automatically display or hide the scroll bars and do the scrolling. The best thing of the good ideas is that they are simple; the worst thing is that we only got it after having tried many other complicated and unsatisfactory ways.

Full example code:


' ########################################################################################
' Microsoft Windows
' File: CW_COMMCTRL_TabControlDemo.fbtpl - Template
' Contents: CWindow Tab Control template
' Remarks: Demonstrates the use of the CTabPage class
' 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.
' ########################################################################################

#INCLUDE ONCE "Afx/CWindow.inc"
#INCLUDE ONCE "Afx/CScrollWindow.inc"
USING Afx.CWindowClass

CONST IDC_TAB       = 1001
CONST IDC_EDIT1     = 1002
CONST IDC_EDIT2     = 1003
CONST IDC_BTNSUBMIT = 1004
CONST IDC_COMBO     = 1005
CONST IDC_LISTBOX   = 1006

' // Forward declarations
DECLARE FUNCTION TabPage1_WndProc(BYVAL hWnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
DECLARE FUNCTION TabPage2_WndProc(BYVAL hWnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
DECLARE FUNCTION TabPage3_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)

' ========================================================================================
' 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)
            ' // If ESC key pressed, close the application sending an WM_CLOSE message
            CASE IDCANCEL
               IF HIWORD(wParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE WM_GETMINMAXINFO
         ' Set the pointer to the address of the MINMAXINFO structure
         DIM ptmmi AS MINMAXINFO PTR = CAST(MINMAXINFO PTR, lParam)
         ' Set the minimum and maximum sizes that can be produced by dragging the borders of the window
         DIM pWindow AS CWindow PTR = AfxCWindowPtr(hwnd)
         IF pWindow THEN
            ptmmi->ptMinTrackSize.x = 460 * pWindow->rxRatio
            ptmmi->ptMinTrackSize.y = 320 * pWindow->ryRatio
         END IF
         EXIT FUNCTION

      CASE WM_SIZE
         DIM pWindow AS CWindow PTR = AfxCWindowPtr(hwnd)
         DIM hTab AS HWND = GetDlgItem(hwnd, IDC_TAB)
         ' / Move the close button
         IF pWindow THEN pWindow->MoveWindow GetDlgItem(hwnd, IDCANCEL), pWindow->ClientWidth - 85, pWindow->ClientHeight - 28, 75, 23, CTRUE
         ' // Resize the tab control
         IF pWindow THEN pWindow->MoveWindow(hTab, 10, 10, pWindow->ClientWidth - 20, pWindow->ClientHeight - 42, CTRUE)
         ' // Resize the tab pages
         AfxResizeTabPages hTab
         EXIT FUNCTION

      CASE WM_NOTIFY

         DIM nPage AS DWORD              ' // Page number
         DIM pTabPage AS CTabPage PTR    ' // Tab page object reference
         DIM tci AS TCITEMW              ' // TCITEMW structure

         DIM ptnmhdr AS NMHDR PTR   ' // Information about a notification message
         ptnmhdr = CAST(NMHDR PTR, lParam)
         SELECT CASE ptnmhdr->idFrom
            CASE IDC_TAB
               SELECT CASE ptnmhdr->code
                  CASE TCN_SELCHANGE
                     ' // Show the selected page
                     pTabPage = AfxCTabPagePtr(ptnmhdr->hwndFrom)
                     IF pTabPage THEN ShowWindow pTabPage->hTabPage, SW_SHOW
                  CASE TCN_SELCHANGING
                     ' // Hide the current page
                     pTabPage = AfxCTabPagePtr(ptnmhdr->hwndFrom)
                     IF pTabPage THEN ShowWindow pTabPage->hTabPage, SW_HIDE
               END SELECT

         END SELECT

    CASE WM_DESTROY
         ' // Destroy the tab pages
         AfxDestroyAllTabPages(GetDlgItem(hwnd, IDC_TAB))
         ' // Quit the application
         PostQuitMessage(0)
         EXIT FUNCTION

   END SELECT

   FUNCTION = DefWindowProcW(hWnd, uMsg, wParam, lParam)

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, "CWindow with a Tab Control", @WndProc)
   pWindow.SetClientSize(500, 320)
   pWindow.Center

   ' // Add a tab control
   DIM hTab AS HWND = pWindow.AddControl("Tab", , IDC_TAB, "", 10, 10, pWindow.ClientWidth - 20, pWindow.ClientHeight - 42)

   ' // Create the first tab page
   DIM pTabPage1 AS CTabPage PTR = NEW CTabPage
   pTabPage1->InsertPage(hTab, 0, "Tab 1", -1, @TabPage1_WndProc)
   ' // Add controls to the first page
   pTabPage1->AddControl("Label", pTabPage1->hTabPage, -1, "First name", 15, 15, 121, 21)
   pTabPage1->AddControl("Label", pTabPage1->hTabPage, -1, "Last name", 15, 50, 121, 21)
   pTabPage1->AddControl("Edit", pTabPage1->hTabPage, IDC_EDIT1, "", 165, 15, 186, 21)
   pTabPage1->AddControl("Edit", pTabPage1->hTabPage, IDC_EDIT2, "", 165, 50, 186, 21)
   pTabPage1->AddControl("Button", pTabPage1->hTabPage, IDC_BTNSUBMIT, "Submit", 340, 185, 76, 26, BS_DEFPUSHBUTTON)

   ' // Create the second tab page
   DIM pTabPage2 AS CTabPage PTR = NEW CTabPage
   pTabPage2->InsertPage(hTab, 1, "Tab 2", -1, @TabPage2_WndProc)
   ' // Add controls to the second page
   DIM hComboBox AS HWND = pTabPage2->AddControl("ComboBox", pTabPage2->hTabPage, IDC_COMBO, "", 20, 20, 191, 105)

   ' // Create the third tab page
   DIM pTabPage3 AS CTabPage PTR = NEW CTabPage
   pTabPage3->InsertPage(hTab, 2, "Tab 3", -1, @TabPage3_WndProc)
   ' // Add controls to the third page
'   DIM hListBox AS HWND = pTabPage3->AddControl("ListBox", pTabPage3->hTabPage, IDC_LISTBOX, "", 15, 20, 161, 120)
   DIM hListBox AS HWND = pTabPage3->AddControl("ListBox", pTabPage3->hTabPage, IDC_LISTBOX)
   pTabPage3->SetWindowPos hListBox, NULL, 15, 20, 161, 120, SWP_NOZORDER

   ' // Fill the controls with some data
   DIM i AS LONG = 1, wszText AS WSTRING * 260
   FOR i = 1 TO 9
      wszText = "Item " & RIGHT("00" & STR(i), 2)
      SendMessageW(hComboBox, CB_ADDSTRING, 0, CAST(LPARAM, @wszText))
      SendMessageW(hListBox, LB_ADDSTRING, 0, CAST(LPARAM, @wszText))
   NEXT
   ' // Select the first item in the combo box and the list box
   SendMessageW(hComboBox, CB_SETCURSEL, 0, 0)
   SendMessageW(hListBox, LB_SETCURSEL, 0, 0)

   ' // Add a button
   pWindow.AddControl("Button", , IDCANCEL, "&Close", 415, 292, 75, 23)

   ' ************************************************************************
   ' // Make the first tab page scrollable
   ' // TODO: Modify the CTabPage class to set the pointer to CScrollWindow
   ' // to delete this class when the tab page is destroyed.
   ' ************************************************************************
   ' // Get the client size of the first page and make it greater
   DIM nWidth AS LONG = pTabPage1->ClientWidth
   DIM nHeight AS LONG = pTabPage1->ClientHeight
   pTabPage1->SetClientSize(nWidth + 150, nHeight + 150)
   ' // Create an instance of the CScrollWindow class and attach the main window to it
   DIM pScrollWindow AS CScrollWindow = pTabPage1->hTabPage
   SetPropW pTabPage1->hTabPage,"CSCROLLWINDOWPTR", @pScrollWindow
   ' // Shrink the client size back to original
   pTabPage1->SetClientSize(nWidth, nHeight)
   ' ************************************************************************

   ' // Display the first tab page
   ShowWindow pTabPage1->hTabPage, SW_SHOW

   ' // Set the focus to the first tab
   SendMessageW hTab, TCM_SETCURFOCUS, 0, 0

   

   ' // Dispatch messages
   FUNCTION = pWindow.DoEvents(nCmdShow)

END FUNCTION
' ========================================================================================

' ========================================================================================
' Tab page 1 window procedure
' To get a pointer to the CTabPage interface:
' DIM pTabPage AS CTabPage PTR = CAST(CTabPage PTR, GetWindowLongPtr(hwnd, 0))
' ========================================================================================
FUNCTION TabPage1_WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   SELECT CASE uMsg

      CASE WM_COMMAND
         SELECT CASE LOWORD(wParam)
            CASE IDC_BTNSUBMIT
               IF HIWORD(wParam) = BN_CLICKED THEN
                  MessageBoxW(hWnd, "Submit", "Tab 1", MB_OK)
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE WM_SIZE
         DIM pScrollWindow AS CScrollWindow PTR = CAST(CScrollWindow PTR, GetPropW(hwnd, "CSCROLLWINDOWPTR"))
         IF pScrollWindow THEN pScrollWindow->OnSize(wParam, lParam)
         EXIT FUNCTION

      CASE WM_VSCROLL
         DIM pScrollWindow AS CScrollWindow PTR = CAST(CScrollWindow PTR, GetPropW(hwnd, "CSCROLLWINDOWPTR"))
         IF pScrollWindow THEN pScrollWindow->OnVScroll(wParam, lParam)
         EXIT FUNCTION

      CASE WM_HSCROLL
         DIM pScrollWindow AS CScrollWindow PTR = CAST(CScrollWindow PTR, GetPropW(hwnd, "CSCROLLWINDOWPTR"))
         IF pScrollWindow THEN pScrollWindow->OnHScroll(wParam, lParam)
         EXIT FUNCTION

      CASE WM_DESTROY
         ' // Remove the property
         RemovePropW hwnd,"CSCROLLWINDOWPTR"
         EXIT FUNCTION

   END SELECT

   FUNCTION = DefWindowProcW(hwnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================

' ========================================================================================
' Tab page 2 window procedure
' To get a pointer to the CTabPage interface:
' DIM pTabPage AS CTabPage PTR = CAST(CTabPage PTR, GetWindowLongPtr(hwnd, 0))
' ========================================================================================
FUNCTION TabPage2_WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   DIM hBrush AS HBRUSH, rc AS RECT, tlb AS LOGBRUSH

   SELECT CASE uMsg

      CASE WM_ERASEBKGND
         GetClientRect hWnd, @rc
         ' Create custom brush
         tlb.lbStyle = BS_SOLID
         tlb.lbColor = &H00CB8734
         tlb.lbHatch = 0
         hBrush = CreateBrushIndirect(@tlb)
         ' Erase background
         FillRect CAST(HDC, wParam), @rc, hBrush
         DeleteObject hBrush
         FUNCTION = CTRUE
         EXIT FUNCTION

   END SELECT

   FUNCTION = DefWindowProcW(hwnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================

' ========================================================================================
' Tab page 3 window procedure
' To get a pointer to the CTabPage interface:
' DIM pTabPage AS CTabPage PTR = CAST(CTabPage PTR, GetWindowLongPtr(hwnd, 0))
' ========================================================================================
FUNCTION TabPage3_WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   DIM hBrush AS HBRUSH, rc AS RECT, tlb AS LOGBRUSH

   SELECT CASE uMsg

      CASE WM_ERASEBKGND
         GetClientRect hWnd, @rc
         ' Create custom brush
         tlb.lbStyle = BS_SOLID
         tlb.lbColor = &H0000FF00
         tlb.lbHatch = 0
         hBrush = CreateBrushIndirect(@tlb)
         ' Erase background
         FillRect CAST(HDC, wParam), @rc, hBrush
         DeleteObject hBrush
         FUNCTION = CTRUE
         EXIT FUNCTION

   END SELECT

   FUNCTION = DefWindowProcW(hwnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================

Title: Re: CWindow RC10
Post by: José Roca on June 22, 2016, 12:08:41 AM
I have added the ScrollWindowPtr property to CWindow.

Now we can use


   ' // Create an instance of the CScrollWindow class and attach the main window to it
   DIM pScrollWindow AS CScrollWindow PTR = NEW CScrollWindow(hwndMain)
   pWindow.ScrollWindowPtr = pScrollWindow


and don't have to worry about destroying the CScrollWindow class, that will be destroyed by CWindow.

Also we don't need to use SetPropW, etc., but we can use:


      CASE WM_VSCROLL
         DIM pScrollWindow AS CScrollWindow PTR = AfxCWindowPtr(hwnd)->ScrollWindowPtr
         IF pScrollWindow THEN pScrollWindow->OnVScroll(wParam, lParam)
         EXIT FUNCTION


Regarding tab pages, we will use:


   ' // Create an instance of the CScrollWindow class and attach the tab page handle to it
   DIM pScrollWindow AS CScrollWindow PTR = NEW CScrollWindow(pTabPage1->hTabPage)
   pTabPage1->ScrollWindowPtr = pScrollWindow


and as the pointer to the class is not stored in the tab page, but in the tab control...


      CASE WM_VSCROLL
         DIM pScrollWindow AS CScrollWindow PTR = AfxCTabPagePtr(GetParent(hwnd))->ScrollWindowPtr
         IF pScrollWindow THEN pScrollWindow->OnVScroll(wParam, lParam)
         EXIT FUNCTION

Title: Re: CWindow RC10
Post by: José Roca on June 22, 2016, 01:11:30 AM
We could even use this compound syntax:


AfxCWindowPtr(hwnd)->ScrollWindowPtr->OnSize(wParam, lParam)



DIM pScrollWindow AS CScrollWindow PTR = AfxCWindowPtr(hwnd)->ScrollWindowPtr
IF pScrollWindow THEN pScrollWindow->OnVScroll(wParam, lParam)


but it's unsafe, because if ScrollWindowPtr returns a null pointer it will GPF.

Only with a compiler with full support for compound syntax could we use it safely. The compiler will check if the result of AfxCWindowPtr(hwnd)->ScrollWindowPtr is null or not and, if it is null, will not call OnVScroll(wParam, lParam). This is what I requested to the late Bob Zale because without this feature, the compound syntax is unsafe.