home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Programmierung / SOURCE.mdf / programm / windows / c / bsscdemo / treedem1 / treedem1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-25  |  37.4 KB  |  868 lines

  1. /*
  2.    Copyright (c) 1993 by Barking Spider Software, Inc.  All rights reserved
  3.                                                                            
  4.    Filename...:  treedem1.c
  5.    
  6.    Version,,,,:  1.0
  7.    
  8.    Language...:  Microsoft C/C++ 7.0
  9.    
  10.    Model......:  Small
  11.    
  12.    Environment:  Microsoft Windows 3.1
  13.                                                                            
  14.    Description:  This source module demonstrates the BSS Tree Control.  It 
  15.                  is a very simple example.  It just creates a tree and
  16.                  provides the minimum support.  One top level window is
  17.                  created similar to the standard GENERIC app.  In the
  18.                  handling of the WM_CREATE message in this window's
  19.                  associated window procedure, the BSS Tree Control is
  20.                  created and a root tree node is inserted into the empty
  21.                  tree along with five children to this node.
  22.                  
  23.                  The user is then able to double click on any of the nodes.
  24.                  Initially since all of the nodes are closed except the root,
  25.                  double clicking on any of the closed nodes will add five
  26.                  child nodes to the node which was selected.
  27.                  
  28.                  If the user clicks on a node which is opened (has children)
  29.                  then the five children of the selected node will be deleted.
  30.                  
  31.                  To close the application, the user selects the Close option
  32.                  in the system menu.
  33.                  
  34.                  The below code shows how to create a tree, add nodes, delete
  35.                  nodes and the clean-up process for destroying the tree.
  36.                  
  37.                  For more documentation on the BSS Tree Control APIs,
  38.                  structures, notifications, and error codes, refer to the
  39.                  header file BSTREE.H.
  40.    Notes......:             
  41.                                                                            
  42.    History....:  
  43.                                                                               
  44.    Author.....:  Peter J. Kaufman
  45. */    
  46.  
  47. #include <windows.h>
  48. #include "treedem1.h"
  49. #include "..\bscore.h"
  50. #include "..\bstree.h"
  51.  
  52. static char szAppName[] = "TreeDem1" ;
  53. HANDLE hInst ;
  54.  
  55.  
  56. /*****************************************************************************
  57. int PASCAL WinMain ( HANDLE hInstance,
  58.                      HANDLE hPrevInstance,
  59.                      LPSTR lpszCmdLine,
  60.                      int nCmdShow);
  61.                      
  62. *****************************************************************************/
  63.  
  64. int PASCAL WinMain ( HANDLE hInstance,
  65.                      HANDLE hPrevInstance,
  66.                      LPSTR lpszCmd,
  67.                      int nCmdShow)
  68. {
  69.    HWND       hwnd ;
  70.    MSG        msg ;
  71.    WNDCLASS   wndclass ;
  72.  
  73.    hInst = hInstance ;
  74.  
  75.    if (!hPrevInstance)
  76.    {
  77.       wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
  78.       wndclass.lpfnWndProc   = TreeDemo1WndProc ;
  79.       wndclass.cbClsExtra    = 0 ;
  80.       wndclass.cbWndExtra    = 0 ;
  81.       wndclass.hInstance     = hInst;
  82.       wndclass.hIcon         = LoadIcon (hInst,
  83.                                          MAKEINTRESOURCE(IDR_TREEDEMO_ICON)) ;
  84.       wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  85.       wndclass.hbrBackground = COLOR_APPWORKSPACE + 1;
  86.       wndclass.lpszMenuName  = NULL ;
  87.       wndclass.lpszClassName = szAppName ;
  88.  
  89.       RegisterClass (&wndclass) ;
  90.    }
  91.  
  92.    hwnd = CreateWindow (szAppName,
  93.                         "Barking Spider Software, Inc. Tree Demo 1",
  94.                         WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  95.                         CW_USEDEFAULT,
  96.                         CW_USEDEFAULT,
  97.                         CW_USEDEFAULT,
  98.                         CW_USEDEFAULT,
  99.                         NULL,
  100.                         NULL,
  101.                         hInstance,
  102.                         NULL);
  103.  
  104.    ShowWindow (hwnd, nCmdShow) ;
  105.    UpdateWindow (hwnd) ;
  106.  
  107.    while (GetMessage (&msg, NULL, 0, 0))
  108.    {
  109.       TranslateMessage (&msg) ;
  110.       DispatchMessage (&msg) ;
  111.    }
  112.    return msg.wParam ;
  113. }
  114.  
  115.  
  116.  
  117. /*****************************************************************************
  118. long FAR PASCAL _export TreeDemo1WndProc ( HWND hwnd,
  119.                                            UINT message,
  120.                                            UINT wParam,
  121.                                            LONG lParam)
  122.                      
  123.  
  124.  Shows the process of creating a BSS Tree Control, the adding and deleting of
  125.  children, and the clean-up process when destroying the tree.
  126.  
  127.  The number of children a node can have is hardwired for simplicity and the
  128.  text string for each tree node is almost identical except for the index
  129.  number at the end of the string.
  130. *****************************************************************************/
  131.  
  132. HWND    hwndTree;        // Handle of tree control.
  133. HBITMAP hbmClosedActive; // Bitmap handle of closed folder when the tree node
  134.                          // is highlighted.
  135. HBITMAP hbmClosed;       // Bitmap handle of closed folder when the tree node
  136.                          // is NOT highlighted.
  137. HBITMAP hbmOpenActive;   // Bitmap handle of open folder when the tree node
  138.                          // is highlighted.
  139. HBITMAP hbmOpen;         // Bitmap handle of open folder when the tree node
  140.                          // is NOT highlighted.
  141.  
  142. #define MAX_CHILDREN_PER_NODE   5  
  143. #define MAX_SAMPLE_TEXT_LENGTH  512
  144. #define SAMPLE_TEXT             "Sample Tree Node Text"
  145.  
  146.  
  147.  
  148. long FAR PASCAL _export TreeDemo1WndProc ( HWND hwnd,
  149.                                            UINT message,
  150.                                            UINT wParam,
  151.                                            LONG lParam)
  152. {
  153.    LP_TREE_NODE       lpParentTreeNode;// Pointer to tree node
  154.    LP_TREE_NODE_DEF   lpTreeNodeDef;   // Pointer to tree node definition
  155.    LP_TREE_NODE_DEF   lpTreeNodeDef2;
  156.    LP_SELECT_NOTIF    lpSelectNotif;   // Pointer to tree notification struct.
  157.    WORD               i;
  158.    short              cx, cy;
  159.    WORD               wErrCode;
  160.    LONG               lResult;
  161.    WORD               wMaxChildrenPerNode;
  162.    
  163.    switch (message)
  164.    {
  165.       case WM_CREATE:
  166.          lResult = 0xFFFFFFFF;
  167.  
  168.          // BST_CreateTree ( ) creates a BSS Tree Control.  The parameters are
  169.          // similar to the Windows API CreateWindowEx ( ).  Why have the call?
  170.          // The API guarantees that the Window style will include
  171.          // the scroll bars, clipping, and helps the programmer use the 
  172.          // right class.  Notice I added a border to the style.  Looks great!
  173.          // Notice that the starting x, y, width, and height are
  174.          // 0?  This works because the WM_SIZE message handler of this window
  175.          // procedure does a MoveWindow ( ) to the BSS Tree Control to keep
  176.          // the tree control sized to the main window's client area.
  177.          
  178.          hwndTree = BST_CreateTree (hInst, hwnd, 0, 0, 0, 0, WS_BORDER, 0);
  179.          
  180.          if(hwndTree != NULL)  // If the BST_CreateTree ( ) is successful...
  181.          {                                                 
  182.             // The routine CreateBackgroundMatchedBitmap ( ) is defined at
  183.             // the end of this module.  CreateBackgroundMatchedBitmap ( )
  184.             // loads the initial folder bitmaps from the resource,
  185.             // and converts the bitmap background color to match the system 
  186.             // window color.  This is done for the closed and open
  187.             // folder bitmaps.  Since the folders are used for animation
  188.             // and the shapes are non rectangular, the background of the 
  189.             // bitmap must match the window color otherwise the appearance
  190.             // is undesirable.  
  191.             // CreateBackgroundMatchedBitmap ( ) only handles
  192.             // 16 bit color bitmaps. 
  193.             
  194.             // Notice that this procedure is also called for the
  195.             // COLOR_HIGHLIGHT color.  COLOR_HIGHLIGHT is the color used to
  196.             // show the current selection (active node).  Feel free to
  197.             // include this and any other routine in your application if the
  198.             // need for background masking is needed.
  199.    
  200.             hbmClosed = CreateBackgroundMatchedBitmap (
  201.                                                    GetSysColor (COLOR_WINDOW),
  202.                                                    IDR_CLOSED_FOLDER);
  203.    
  204.             hbmClosedActive = CreateBackgroundMatchedBitmap (
  205.                                                 GetSysColor (COLOR_HIGHLIGHT),
  206.                                                 IDR_CLOSED_FOLDER);
  207.    
  208.             hbmOpen = CreateBackgroundMatchedBitmap (
  209.                                                    GetSysColor (COLOR_WINDOW),
  210.                                                    IDR_OPEN_FOLDER);
  211.             
  212.             hbmOpenActive = CreateBackgroundMatchedBitmap (
  213.                                                  GetSysColor (COLOR_HIGHLIGHT),
  214.                                                  IDR_OPEN_FOLDER);
  215.                                                    
  216.             // Bitmaps spaces are regions where bitmaps are displayed for the
  217.             // tree node.  Bitmap spaces encompass the bitmaps or icons.
  218.             // The bitmap spaces are placed left of the text.  
  219.             
  220.             // From left to right the left most bitmap space has an index
  221.             // value of 0, the next bitmap space has an index value of 1,
  222.             //  and so on.
  223.  
  224.             // When a bitmap space is defined, it is defined for the entire
  225.             // tree, for all tree nodes.  For example, if the left most bitmap
  226.             // space is defined to have a width of 30 pixels and a height of
  227.             // 20 pixels, then all the bitmaps placed in this bitmap space
  228.             // for all the tree nodes will have to fit into these dimensions.
  229.             // The reasoning behind this, is that it forces column alignment
  230.             // of the bitmaps for a given bitmap space and offers a
  231.             //  consistency in hit testing.  Hit testing is performed on the
  232.             // bitmap space, not just on the bitmap.
  233.             
  234.             // Below, the left most bitmap space is defined.  The max width
  235.             // and height are defined.  The first argument is the BSS Tree
  236.             // Control handle, the second is the bitmap space identifier or
  237.             // index.  The third and fourth arguments are the width and
  238.             // height respectively.  The last argument signals to the BSS Tree
  239.             // Control whether to center or left justify the currently
  240.             // assigned bitmap in this bitmap space.  TRUE means center,
  241.             // FALSE means left justify.
  242.             
  243.             // Instead of hard code values for the width and height, another
  244.             // could be taken.  If the item to be assigned to the below
  245.             // bitmap space is a bitmap, then a call to
  246.             //  GetObject (hBitmap, sizeof(BITMAP), (LPSTR) &bm);
  247.             // could be called and the dimensions of the bitmap could be
  248.             // used along with some padding to define the width and height
  249.             // of the bitmap space.
  250.             // If the item to be assigned to the below bitmap space is an
  251.             // icon, then the values from the calls to
  252.             // GetSystemMetrics (SM_CXICON) and  GetSystemMetrics (SM_CYICON) 
  253.             // could be used along with some padding to define the width
  254.             // and height of the bitmap space.  Since the Windows GDI
  255.             // call DrawIcon ( ) is used to draw the icon by the tree
  256.             // control, if a bitmap space is to contain an icon then the
  257.             // width and height must be defined the described method above.
  258.             
  259.             BST_SetBitmapSpace( hwndTree, 0, 23, 17, TRUE);
  260.             
  261.             // Now, the fun part...  Defining tree nodes.
  262.             // First... define the root!
  263.             
  264.             // Allocate one (1) tree node definition for the root. It
  265.             // is best if this memory is initialize to zero.  Any members
  266.             // of the TREE_NODE_DEF structure that are not defined must be
  267.             // initialized with zero.  The tree node
  268.             // definition structure is the vehicle that the application uses
  269.             // to define tree nodes to the BSS Tree Control.  This memory is 
  270.             // the property of the application.  It's contents are copied to 
  271.             // the tree control.  Once the node is defined, this memory can
  272.             // be freed.
  273.    
  274.             // Note.  GlobalAlloc ( ) returns the segment and not the handle
  275.             // of the allocated memory since the GMEM_FIXED flag is applied 
  276.             // which requests that the memory block is fixed in memory.  Also,
  277.             // since the GMEM_ZEROINIT flag is applied, the memory is zeroed.
  278.             // MAKEP ( ) macro converts this segment into a long
  279.             // pointer (segment:0).  The GMEM_SHARE flag is used since
  280.             // the pointer is passed to the tree control in the process
  281.             // of defining new tree nodes.
  282.             
  283.             lpTreeNodeDef = (LP_TREE_NODE_DEF)
  284.                   MAKEP( GlobalAlloc (GMEM_FIXED | GMEM_ZEROINIT | GMEM_SHARE, 
  285.                                 MAKELONG( sizeof (TREE_NODE_DEF) * 1, 0)), 0);
  286.                                         
  287.             
  288.             if( lpTreeNodeDef )  // If the above memory allocation is success...
  289.             {
  290.                // Assign the text that will be displayed for the tree node.
  291.             
  292.                // Normally, the tree control will allocate wTextLength + 1 
  293.                // worth of memory to store a copy of the string pointed to by 
  294.                // lpszText when the tree node is created since the supplied
  295.                // pointer can become invalid if the string it points to is
  296.                // moved or deleted in the future.
  297.                
  298.                lpTreeNodeDef->lpszText = "You cannot have a tree without a root.";
  299.                
  300.                // Assign the length of the above text to the wTextLength
  301.                // member.  This tells the tree control, how many character
  302.                // to display.
  303.                
  304.                // Note. If the sign bit of the wTextLength member is set to 1 
  305.                // by the application then this signals the tree
  306.                // control NOT to allocate memory for the string pointed to by
  307.                // lpszText, above,  but just store and use the supplied string
  308.                // pointer directly to display the tree node's text.
  309.                // This would work in the case of string assigned
  310.                // to the lpszText member, above, because it is a constant and
  311.                // is guaranteed to be in the application's data segment for
  312.                // the life of the application.  It will not be applied here
  313.                // though, since this is suppose to be a simple demo.
  314.                // The advantage of this technique is two fold.  A double
  315.                // allocation of the string is performed and the speed in
  316.                // creating the new tree node is much faster since the
  317.                // tree control does not have to allocate memory for the
  318.                // string and copy it.
  319.       
  320.                lpTreeNodeDef->wTextLength = lstrlen(lpTreeNodeDef->lpszText);
  321.                
  322.                // Now it's time to assign bitmap handles created earlier to
  323.                // the first bitmap space which was defined earlier as well.
  324.                // Currently, there are three bitmap spaces allowed to be
  325.                // defined per node.  If more are needed, then the source can
  326.                // be purchased and the number of bitmap spaces can be
  327.                // increased.  In most case only two bitmaps are good enough.
  328.                // If any of the bitmap spaces are not used or the 
  329.                // corresponding bitmap/icon handle will be defined later, then
  330.                // make sure that all unused hBitmap[] and hActiveBitmap[]
  331.                // array elements are set to NULL.  The tree control does
  332.                // not check the validity of a bitmap/icon handle.  
  333.                
  334.                // Bitmap/icon handles can be assigned to bitmap spaces, at
  335.                // a later time by calling BST_SetBitmap ( ) and/or 
  336.                // BST_SetIcon ( ).
  337.                lpTreeNodeDef->chBitmapTypeBits = 0x0000;
  338.                
  339.                lpTreeNodeDef->hBitmap[0] = hbmClosed;
  340.       
  341.                lpTreeNodeDef->hActiveBitmap[0] = hbmClosedActive;
  342.       
  343.                // Notice that the hActiveBitmap[] counterparts are not
  344.                // set to NULL.  The tree control will NOT reference
  345.                // their associated hActiveBitmap[] if hBitmap[] is
  346.                // set to NULL.
  347.                lpTreeNodeDef->hBitmap[1] = NULL;
  348.                lpTreeNodeDef->hBitmap[2] = NULL;
  349.                
  350.                // No user-defined data associated with the node.
  351.                lpTreeNodeDef->lpUserData = NULL;
  352.                lpTreeNodeDef->wUserDataSize = 0;
  353.       
  354.                // Since the tree node definition structure is defined then
  355.                // the call to BST_AddChildrenToParent ( ) needs to be 
  356.                // performed.  Notice the 0L value.
  357.                // This is the indicator that this node is the root.  The tree
  358.                // can only have one root.  If the root is NOT defined then
  359.                // calling any other tree control exported API will be
  360.                // ignored.
  361.       
  362.                wErrCode = BST_AddChildrenToParent(hwndTree, 0L,1,lpTreeNodeDef);
  363.  
  364.                // HandleAddChildrenError ( ) is defined below.  
  365.                
  366.                if(HandleAddChildrenError( hwnd, wErrCode) == 0)
  367.                {
  368.                   // No error so continue...
  369.                   
  370.                   // The lpTreeNode member of the TREE_NODE_DEF structure 
  371.                   // is an important animal.  When 
  372.                   // BST_AddChildrenToParent ( ) is called with the tree node
  373.                   // definitions, the tree control internally allocates the
  374.                   // memory to store the tree node definition information, and
  375.                   // assigns the pointer to this memory to the tree node
  376.                   // definition member 'lpTreeNode'.  Remember, the tree node
  377.                   // definition structure is shared memory between the
  378.                   // application and the tree control.  The application will
  379.                   // use the 'lpTreeNode' value for future references to the
  380.                   // new node such as adding nodes as children.
  381.                   
  382.                   // Below, the 'lpTreeNode' member of the tree node definition
  383.                   // is saved.  It will be used as a reference (parent) to add
  384.                   // children.
  385.          
  386.                   lpParentTreeNode = lpTreeNodeDef->lpTreeNode;
  387.          
  388.          
  389.                   // Free the TREE_NODE_DEF allocation for the root since
  390.                   // it is not needed anymore.
  391.                   
  392.                   FREEP(lpTreeNodeDef);
  393.                   
  394.                   // Next... define the children of the root.
  395.                   // Allocate the memory (application grown and owned).
  396.                 
  397.                   // Note.  GlobalAlloc ( ) returns the segment and not the
  398.                   // handle of the allocated memory since the GMEM_FIXED flag
  399.                   // is applied which requests that the memory block is fixed
  400.                   // in memory.  Also, since the GMEM_ZEROINIT flag is applied,
  401.                   // the memory is zeroed.  MAKEP ( ) macro converts this
  402.                   // segment into a long pointer (segment:0).  The GMEM_SHARE
  403.                   // flag is used since the pointer is passed to the tree
  404.                   // control in the process of defining new tree nodes.
  405.  
  406.                   wMaxChildrenPerNode = MAX_CHILDREN_PER_NODE;
  407.          
  408.                   lpTreeNodeDef = (LP_TREE_NODE_DEF)
  409.                     MAKEP( GlobalAlloc ( GMEM_FIXED|GMEM_ZEROINIT|GMEM_SHARE,
  410.                           MAKELONG(sizeof(TREE_NODE_DEF)* 
  411.                                           wMaxChildrenPerNode ,0)),0);
  412.          
  413.                   // Traverse the memory, initializing text, text length,
  414.                   // bitmaps, etc.
  415.                   
  416.                   if ( lpTreeNodeDef )
  417.                   {
  418.                      lpTreeNodeDef2 = lpTreeNodeDef; 
  419.             
  420.                      for (i = 0; 
  421.                           i < wMaxChildrenPerNode;
  422.                           i++, lpTreeNodeDef2++)
  423.                      {
  424.                         if((lpTreeNodeDef2->lpszText = 
  425.                           MAKEP(GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT|GMEM_SHARE,
  426.                                       MAX_SAMPLE_TEXT_LENGTH),0)) != NULL)
  427.                         {
  428.                            // CAUTION: wsprintf has an internal buffer size
  429.                            // limit.
  430.                            wsprintf (lpTreeNodeDef2->lpszText, "%s %d.", 
  431.                                                        (LPSTR) SAMPLE_TEXT, i);
  432.                            lpTreeNodeDef2->wTextLength
  433.                                            = lstrlen(lpTreeNodeDef2->lpszText);
  434.                            
  435.                            lpTreeNodeDef2->chBitmapTypeBits = 0x0000;
  436.                            
  437.                            lpTreeNodeDef2->hBitmap[0] = hbmClosed;
  438.                            lpTreeNodeDef2->hActiveBitmap[0] = hbmClosedActive;
  439.                            
  440.                            lpTreeNodeDef2->hBitmap[1] = NULL;
  441.                            lpTreeNodeDef2->hBitmap[2] = NULL;
  442.                            
  443.                             // No user-defined data associated with the node.
  444.                            lpTreeNodeDef2->lpUserData = NULL;
  445.                            lpTreeNodeDef2->wUserDataSize = 0;
  446.                             
  447.                         }
  448.                         else
  449.                         {
  450.                            wMaxChildrenPerNode = i;
  451.                            MessageBox ( hwnd, 
  452.                                         "Out of memory.",
  453.                                         "WM_CREATE",
  454.                                         MB_OK);
  455.                         }
  456.                      }          
  457.                      
  458.                      // Add the children to the parent 'lpTreeNode'.
  459.                      // We do not need to store the tree node pointers that 
  460.                      // are returned in the 'lpTreeNode' member of the
  461.                      // TREE_NODE_DEF structures.  
  462.                      // This application will rely on the notification message
  463.                      // that will be sent to the application as a result of
  464.                      // an event, such as a double click of the mouse.  The
  465.                      // notification message will supply the pointer to the
  466.                      // tree node involved in the event.
  467.             
  468.                      wErrCode  = BST_AddChildrenToParent( hwndTree,
  469.                                                           lpParentTreeNode,   // Parent which is the root
  470.                                                           wMaxChildrenPerNode,
  471.                                                           lpTreeNodeDef);
  472.             
  473.                      if(HandleAddChildrenError( hwnd, wErrCode) == 0)
  474.                      {
  475.                         // No error so the parent tree node now
  476.                         // has children so open the folder.
  477.                         BST_SetBitmapAndActiveBitmap( hwndTree,
  478.                                                       0,
  479.                                                       lpParentTreeNode,
  480.                                                       hbmOpen,
  481.                                                       hbmOpenActive);                
  482.              
  483.                      }
  484.                      
  485.                      // Traverse through the TREE_NODE_DEF structures, 
  486.                      // freeing the string memory.   Once this is completed
  487.                      // then the TREE_NODE_DEF array needs to be freed.
  488.                      lpTreeNodeDef2 = lpTreeNodeDef;
  489.                                                  
  490.                      for (i = 0;
  491.                           i < wMaxChildrenPerNode;
  492.                           i++, lpTreeNodeDef2++)
  493.                      {
  494.                         FREEP(lpTreeNodeDef2->lpszText);
  495.                      } 
  496.                      FREEP(lpTreeNodeDef);
  497.                   }
  498.                   else
  499.                   {
  500.                      MessageBox (hwnd, "Out of memory.", "WM_CREATE",MB_OK);
  501.                   }
  502.                   // Set focus to the tree control, show it, and let 
  503.                   // the user knock herself or himself out.
  504.                   
  505.                   SetFocus (hwndTree);
  506.                   ShowWindow (hwndTree, SW_SHOW);
  507.                   lResult = 0L;
  508.                }
  509.             }
  510.             else
  511.             {
  512.                MessageBox (hwnd, "Out of memory.", "WM_CREATE",MB_OK);
  513.             }
  514.          }
  515.          return lResult ;
  516.  
  517.  
  518.       case WM_BST_SELECT_NOTIF_DBLCLK:
  519.       
  520.          // WM_BST_SELECT_NOTIF_DBLCLK is a notification message sent to
  521.          // the application when the user:
  522.          // 1)  double clicks on a tree node,
  523.          // 2)  hits the carriage return (acts as if the currently highlighted
  524.          //     node was double clicked on.),
  525.          // 3)  hits the '+' key if the currently highlighted node has children,
  526.          // 4)  hits the '-' key if the currently highlighted node has no
  527.          //     children.
  528.          // lParam is a pointer to a SELECT_NOTIF notification structure which
  529.          // is owned by the tree control.  DO NOT FREE THIS MEMORY OR ALL
  530.          // HELL WILL BREAK LOOSE.  The members of the SELECT_NOTIF structure
  531.          // consist of the pointer to the tree node that was selected and a
  532.          // flags member that describes what region of the tree node which
  533.          // was clicked and if the tree node had children or not (OPEN or
  534.          // CLOSED).
  535.  
  536.          lpSelectNotif = (LP_SELECT_NOTIF) lParam;
  537.  
  538.          // lpParentTreeNode is the pointer to the tree control owned 
  539.          // TREE_NODE structure that describes the tree node that was selected.
  540.          
  541.          lpParentTreeNode = lpSelectNotif->lpTreeNode;
  542.          
  543.          // Is the selected tree node OPENED?  OPENED means that the 
  544.          // selected tree node has children.  CLOSED means that the selected
  545.          // tree node has no children.                 
  546.  
  547.          if(lpSelectNotif->wFlags & NODE_OPENED)
  548.          {
  549.             // Yes... then delete the children.  wParam is the handle to 
  550.             // the tree control windows that generated this notification
  551.             // message.
  552.             
  553.             BST_DeleteChildrenOfParent( (HWND)wParam, lpParentTreeNode);
  554.  
  555.             // Close the folder
  556.             BST_SetBitmapAndActiveBitmap( wParam,
  557.                                           0,
  558.                                           lpParentTreeNode,
  559.                                           hbmClosed,
  560.                                           hbmClosedActive);
  561.             }
  562.          else
  563.          {
  564.             // No... then open it and add children if this tree node gots them.
  565.  
  566.             
  567.             // Define the children as in WM_CREATE: but use the 
  568.             // tree node pointer defined in the SELECT_NOTIF structure 
  569.             // member 'lpTreeNode' as the parent.
  570.             
  571.             wMaxChildrenPerNode = MAX_CHILDREN_PER_NODE;
  572.             
  573.             lpTreeNodeDef = (LP_TREE_NODE_DEF)
  574.                   MAKEP(GlobalAlloc( GPTR | GMEM_SHARE, 
  575.                       MAKELONG(sizeof(TREE_NODE_DEF)* wMaxChildrenPerNode ,0)),0);
  576.             
  577.             if( lpTreeNodeDef )
  578.             {  
  579.                lpTreeNodeDef2 = lpTreeNodeDef;
  580.                
  581.                for (i = 0;
  582.                     i < wMaxChildrenPerNode;
  583.                     i++, lpTreeNodeDef2++)
  584.                { 
  585.                   if((lpTreeNodeDef2->lpszText = 
  586.                          MAKEP(GlobalAlloc(GPTR|GMEM_SHARE,
  587.                                       MAX_SAMPLE_TEXT_LENGTH),0)) != NULL)
  588.                   {
  589.                      wsprintf (lpTreeNodeDef2->lpszText, "%s %d.", 
  590.                                                        (LPSTR) SAMPLE_TEXT, i);
  591.                      
  592.                      lpTreeNodeDef2->wTextLength 
  593.                                             = lstrlen(lpTreeNodeDef2->lpszText);
  594.       
  595.                      lpTreeNodeDef2->chBitmapTypeBits = 0x0000;
  596.       
  597.                      lpTreeNodeDef2->hBitmap[0] = hbmClosed;
  598.                      lpTreeNodeDef2->hActiveBitmap[0] = hbmClosedActive;
  599.                         
  600.                      lpTreeNodeDef2->hBitmap[1] = NULL;
  601.                      lpTreeNodeDef2->hBitmap[2] = NULL;
  602.                      
  603.                      // No user-defined data associated with the node.
  604.                      lpTreeNodeDef2->lpUserData = NULL;
  605.                      lpTreeNodeDef2->wUserDataSize = 0;                     
  606.                   }
  607.                   else
  608.                   {   
  609.                      wMaxChildrenPerNode = i;
  610.                      MessageBox ( hwnd,
  611.                                   "Out of memory.", 
  612.                                   "WM_BST_SELECT_NOTIF_DBLCLK",
  613.                                   MB_OK);
  614.                   }
  615.                }
  616.                // Add 'em ...
  617.                
  618.                wErrCode = BST_AddChildrenToParent( wParam,
  619.                                                    lpParentTreeNode,
  620.                                                    wMaxChildrenPerNode,
  621.                                                    lpTreeNodeDef);
  622.                                         
  623.                if(HandleAddChildrenError( wParam, wErrCode) == 0)
  624.                {
  625.                   // If not error then open the folder
  626.                   BST_SetBitmapAndActiveBitmap( wParam,
  627.                                                 0,
  628.                                                 lpParentTreeNode,
  629.                                                 hbmOpen,
  630.                                                 hbmOpenActive);         
  631.                }
  632.                lpTreeNodeDef2 = lpTreeNodeDef;
  633.                                         
  634.                for (i = 0;
  635.                     i < wMaxChildrenPerNode;
  636.                     i++, lpTreeNodeDef2++)
  637.                {
  638.                   FREEP(lpTreeNodeDef2->lpszText);
  639.                }
  640.                FREEP(lpTreeNodeDef);
  641.             }
  642.             else
  643.             {
  644.                MessageBox ( hwnd,
  645.                             "Out of memory.", 
  646.                             "WM_BST_SELECT_NOTIF_DBLCLK",
  647.                             MB_OK);            
  648.             }
  649.          }
  650.          return 0;
  651.  
  652.  
  653.       case WM_SYSCOLORCHANGE:
  654.  
  655.          // Sad but true...  The WM_SYSCOLORCHANGE notification has be sent
  656.          // to the tree control since only top level windows get this
  657.          // notification.  Since the colors are going to change in the 
  658.          // tree control, better make sure that the background color of
  659.          // the bitmaps is correct.
  660.  
  661.          if(hwndTree)
  662.          {
  663.             ChangeBitmapToMatchBackground ( GetSysColor (COLOR_WINDOW),
  664.                                             hbmClosed,
  665.                                             IDR_CLOSED_FOLDER);
  666.             ChangeBitmapToMatchBackground ( GetSysColor (COLOR_WINDOW),
  667.                                             hbmOpen,
  668.                                             IDR_OPEN_FOLDER);
  669.             ChangeBitmapToMatchBackground ( GetSysColor (COLOR_HIGHLIGHT),
  670.                                             hbmClosedActive,
  671.                                             IDR_CLOSED_FOLDER);
  672.             ChangeBitmapToMatchBackground ( GetSysColor (COLOR_HIGHLIGHT),
  673.                                             hbmOpenActive,
  674.                                             IDR_OPEN_FOLDER);
  675.             SendMessage (hwndTree, message, wParam, lParam);
  676.          }
  677.          return 0;       
  678.  
  679.       case WM_SETFOCUS:
  680.          // Keep the focus on the tree control.
  681.          SetFocus(hwndTree);
  682.          break;
  683.          
  684.       case WM_SIZE:
  685.          // Keep the tree control in the client area of the
  686.          // MDI child window.
  687.          cx = GetSystemMetrics ( SM_CXVSCROLL) / 2;
  688.          cy = GetSystemMetrics ( SM_CYHSCROLL) / 2;
  689.          MoveWindow ( hwndTree,
  690.                       cx,
  691.                       cy,
  692.                       max(min(450,LOWORD(lParam) - 2 * cx), 0),
  693.                       max(HIWORD(lParam) - 2 * cy, 0),
  694.                       TRUE);
  695.          break;
  696.     
  697.       case WM_DESTROY:
  698.          BST_EraseTree( hwndTree);
  699.       
  700.          DeleteObject(hbmClosed);
  701.          DeleteObject(hbmClosedActive);
  702.          DeleteObject(hbmOpen);
  703.          DeleteObject(hbmOpenActive);      
  704.          PostQuitMessage (0) ;
  705.          return 0 ;
  706.    }
  707.    return DefWindowProc (hwnd, message, wParam, lParam) ;
  708. }
  709.  
  710.  
  711.  
  712.  
  713. char * npszAddChildrenErrors [] =
  714. {
  715. "Memory allocation failure.",
  716. "Level limit exceeded.",
  717. "The number of nodes supported has been exceeded.",
  718. "Only on root per tree.",
  719. "Given parent node is invalid.",
  720. "Invalid error code"
  721. };                     
  722.  
  723. WORD HandleAddChildrenError( HWND hwnd, WORD wErrCode)
  724. {
  725.    WORD i;
  726.      
  727.    switch (wErrCode)
  728.    {
  729.       case BST_NO_ERROR:
  730.          i = 0;
  731.          break;
  732.  
  733.       case BST_ERR_MEMORY_ALLOC_FAILED:
  734.          i = 1;
  735.          break;
  736.                      
  737.       case BST_ERR_LEVEL_LIMIT_EXCEEDED:
  738.          i = 2;
  739.          break;
  740.                      
  741.       case BST_ERR_TOO_MANY_NODES:
  742.          i = 3;
  743.          break;
  744.                  
  745.       case BST_ERR_ONLY_ONE_ROOT_ALLOWED: 
  746.          i = 4;
  747.          break;
  748.                      
  749.       case BST_ERR_INVALID_PARENT_FOR_INSERTION:
  750.          i = 5;
  751.          break;
  752.                
  753.       default:
  754.         i = 6;
  755.         break;
  756.    }
  757.    if ( i != 0)
  758.    {
  759.       MessageBox ( hwnd, 
  760.                    npszAddChildrenErrors[i-1],
  761.                    "BST_AddChildrenToParent",
  762.                     MB_OK);
  763.    }
  764.    return i;   
  765. }
  766.  
  767.  
  768.  
  769.  
  770.  
  771. /****************************************************************************
  772.  Below are support routines for the 16 color folder bitmaps used in the
  773.  tree.  
  774.  Enjoy!
  775. ****************************************************************************/
  776. HBITMAP CreateBackgroundMatchedBitmap (DWORD dwrgbBackground, int nBitmapResouce)
  777. {
  778.    HANDLE             hBitmap;
  779.    HANDLE             hRes;
  780.    HANDLE             hResMem;
  781.    LPBITMAPINFOHEADER lpbi;
  782.    DWORD FAR *        lpColorTable;
  783.    LPSTR              lpBits;
  784.    int                bc;
  785.    HDC                hdc;
  786.       
  787.    hRes = FindResource ( hInst,
  788.                          MAKEINTRESOURCE (nBitmapResouce),
  789.                          RT_BITMAP);
  790.                               
  791.    hResMem = LoadResource (hInst, hRes);
  792.    lpbi = (LPBITMAPINFOHEADER) LockResource (hResMem);
  793.          
  794.    lpColorTable = (DWORD FAR *)(lpbi + 1);
  795.    lpBits = (LPSTR) (lpColorTable + 16);
  796.          
  797.    bc = (lpBits[0] & 0xF0) >> 4;
  798.          
  799.    lpColorTable [bc] = RGB( GetBValue (dwrgbBackground),
  800.                             GetGValue (dwrgbBackground),
  801.                             GetRValue (dwrgbBackground));
  802.    hdc = GetDC(NULL);
  803.    hBitmap =  CreateDIBitmap ( hdc,
  804.                                lpbi,
  805.                                (DWORD) CBM_INIT,
  806.                                lpBits,
  807.                                (LPBITMAPINFO) lpbi,
  808.                                DIB_RGB_COLORS);
  809.    ReleaseDC(NULL, hdc);
  810.    UnlockResource (hResMem);
  811.    FreeResource(hResMem);
  812.    return hBitmap;
  813. }
  814.  
  815.  
  816. char   rgchBits [2048];
  817.  
  818. short ChangeBitmapToMatchBackground ( DWORD dwrgbBackground,
  819.                                       HANDLE hBitmap,
  820.                                       int nBitmapResouce)
  821. {
  822.    int                bc;
  823.    HDC                hdc;
  824.    LPBITMAPINFO       lpbi;
  825.    HANDLE             hRes;
  826.    HANDLE             hResMem;
  827.  
  828.    hRes = FindResource ( hInst,
  829.                          MAKEINTRESOURCE (nBitmapResouce),
  830.                          RT_BITMAP);
  831.                               
  832.    hResMem = LoadResource (hInst, hRes);
  833.    lpbi = ( LPBITMAPINFO ) LockResource (hResMem);
  834.    
  835.    hdc = GetDC (NULL);
  836.    
  837.    GetDIBits ( hdc,
  838.                hBitmap,
  839.                0,
  840.                LOWORD(lpbi->bmiHeader.biHeight),
  841.                rgchBits,
  842.                lpbi,
  843.                DIB_RGB_COLORS);
  844.  
  845.    bc = (rgchBits[0] & 0xF0) >> 4;
  846.          
  847.    lpbi->bmiColors[bc].rgbBlue = GetBValue (dwrgbBackground);
  848.    lpbi->bmiColors[bc].rgbGreen = GetGValue (dwrgbBackground);
  849.    lpbi->bmiColors[bc].rgbRed =  GetRValue (dwrgbBackground);
  850.    lpbi->bmiColors[bc].rgbReserved = 0;
  851.  
  852.    SetDIBits(hdc,
  853.              hBitmap,
  854.              0,
  855.              LOWORD(lpbi->bmiHeader.biHeight),
  856.              rgchBits,
  857.              lpbi,
  858.              DIB_RGB_COLORS);
  859.  
  860.    ReleaseDC(NULL, hdc );
  861.    UnlockResource (hResMem);
  862.    FreeResource(hResMem);
  863.    return 0;
  864. }
  865.  
  866. /*--------------------------------- EOF -----------------------------------*/
  867.  
  868.