home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cell06d.zip / libcell / cell.c next >
C/C++ Source or Header  |  1999-02-05  |  64KB  |  1,937 lines

  1. /*
  2. ** Module   :CELL.C
  3. ** Abstract :Cell Toolkit procedures
  4. **
  5. ** Copyright (C) Sergey I. Yevtushenko
  6. ** Log: Sun  08/02/98   Created.
  7. **
  8. */
  9.  
  10. #define INCL_WIN
  11. #define INCL_NLS
  12. #define INCL_DOS
  13. #define INCL_GPI
  14.  
  15. #include <os2.h>
  16. #include <string.h>
  17. #include <stdlib.h>
  18. #include <cell.h>
  19.  
  20. #define TKM_SEARCH_ID       WM_USER+0x1000
  21. #define TKM_QUERY_FLAGS     WM_USER+0x1001
  22. #define TKM_SEARCH_PARENT   WM_USER+0x1002
  23.  
  24. #define TB_ATTACHED         0x00F8
  25.  
  26. /*****************************************************************************
  27. ** Static data
  28. */
  29.  
  30. static CHAR CELL_CLIENT[] = "Uni.Cell.Client";
  31. static CHAR TB_CLIENT[]   = "Uni.Tb.Client";
  32. static CHAR TB_SEPCLASS[] = "Uni.Tb.Separator";
  33. static CHAR ppFont[] = "9.WarpSans";
  34.  
  35. /* Color tables */
  36.  
  37. static LONG lColor[SPLITBAR_WIDTH] =
  38. {
  39.     CLR_BLACK,
  40.     CLR_PALEGRAY,
  41.     CLR_WHITE
  42. };
  43.  
  44. static LONG lColor2[SPLITBAR_WIDTH] =
  45. {
  46.     CLR_WHITE,
  47.     CLR_PALEGRAY,
  48.     CLR_BLACK
  49. };
  50.  
  51. /*****************************************************************************
  52. ** Internal prototypes
  53. */
  54.  
  55. MRESULT EXPENTRY CellProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  56. MRESULT EXPENTRY CellClientProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  57. MRESULT EXPENTRY TbProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  58. MRESULT EXPENTRY TbClientProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  59. MRESULT EXPENTRY TbSeparatorProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  60. MRESULT EXPENTRY BtProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  61. HWND CreateTb(TbDef* pTb, HWND hWndParent, HWND hWndOwner);
  62. void RecalcTbDimensions(HWND hwnd, POINTL *pSize);
  63. BOOL TrackRectangle(HWND hwndBase, RECTL* rclTrack, RECTL* rclBounds);
  64.  
  65. /*****************************************************************************
  66. ** Internal data types
  67. */
  68.  
  69.     /* Cell data, used by subclass proc of splitted window. */
  70.  
  71. typedef struct stCellTb
  72. {
  73.     HWND hWnd;
  74.     struct stCellTb* pNext;
  75. } CellTb;
  76.  
  77. typedef struct
  78. {
  79.     PFNWP pOldProc;
  80.     RECTL rclBnd;
  81.     LONG lType;
  82.     LONG lSplit;
  83.     LONG lSize;
  84.     HWND hwndSplitbar;
  85.     HWND hwndPanel1;
  86.     HWND hwndPanel2;
  87.     CellTb *pCellTb;
  88. } CellCtlData;
  89.  
  90.     /* Toolbar data */
  91.  
  92. typedef struct stTbItemData
  93. {
  94.     PFNWP pOldProc;
  95.     CHAR  cText[TB_BUBBLE_SIZE];
  96. } TbItemData;
  97.  
  98. typedef struct stToolbarCtlData
  99. {
  100.     PFNWP pOldProc;
  101.     HWND hwndParent;
  102.     LONG lState;
  103.     LONG lCount;
  104.  
  105.     BOOL bBubble;
  106.     HWND hwndBubble;
  107.     HWND hwndLast;
  108.  
  109.     HWND  hItems[1];
  110. } TbCtlData;
  111.  
  112. static HAB hab;
  113.  
  114. /*
  115. ******************************************************************************
  116. ** Cell (Splitted view) implementation
  117. ******************************************************************************
  118. */
  119.  
  120. void ShowCell(HWND hwnd, LONG lID, BOOL bAction)
  121. {
  122.     HWND hwndMain = hwnd;
  123.     CellCtlData* pCtlData = 0;
  124.     LONG lCell = 0;
  125.  
  126.     hwnd = CellParentWindowFromID(hwnd, lID);
  127.  
  128.     if(!hwnd)
  129.         return;
  130.  
  131.     pCtlData = (CellCtlData *)WinQueryWindowULong(hwnd, QWL_USER);
  132.  
  133.     if(!pCtlData)
  134.         return;
  135.  
  136.     if(WinQueryWindowUShort(pCtlData->hwndPanel1, QWS_ID) == lID)
  137.         lCell = CELL_HIDE_1;
  138.  
  139.     if(WinQueryWindowUShort(pCtlData->hwndPanel2, QWS_ID) == lID)
  140.         lCell = CELL_HIDE_2;
  141.  
  142.     switch(lCell)
  143.     {
  144.         case CELL_HIDE_1:
  145.             if(bAction == FALSE)
  146.                 pCtlData->lType |= CELL_HIDE_1;
  147.             else
  148.                 pCtlData->lType &= ~CELL_HIDE_1;
  149.             break;
  150.  
  151.         case CELL_HIDE_2:
  152.             if(bAction == FALSE)
  153.                 pCtlData->lType |= CELL_HIDE_2;
  154.             else
  155.                 pCtlData->lType &= ~CELL_HIDE_2;
  156.             break;
  157.     }
  158.  
  159.     if(lCell)
  160.         WinSendMsg(hwnd, WM_UPDATEFRAME, 0, 0);
  161. }
  162.  
  163. LONG GetSplit(HWND hwnd, LONG lID)
  164. {
  165.     CellCtlData* pCtlData = 0;
  166.  
  167.     hwnd = CellWindowFromID(hwnd, lID);
  168.  
  169.     if(!hwnd)
  170.         return 0;
  171.  
  172.     pCtlData = (CellCtlData *)WinQueryWindowULong(hwnd, QWL_USER);
  173.  
  174.     if(!pCtlData)
  175.         return 0;
  176.  
  177.     return pCtlData->lSplit;
  178. }
  179.  
  180. LONG SetSplit(HWND hwnd, LONG lID, LONG lNewSplit)
  181. {
  182.     CellCtlData* pCtlData = 0;
  183.  
  184.     hwnd = CellWindowFromID(hwnd, lID);
  185.  
  186.     if(!hwnd)
  187.         return 0;
  188.  
  189.     pCtlData = (CellCtlData *)WinQueryWindowULong(hwnd, QWL_USER);
  190.  
  191.     if(!pCtlData)
  192.         return 0;
  193.  
  194.     if(!(pCtlData->lType & CELL_FIXED))
  195.     {
  196.         pCtlData->lSplit = lNewSplit;
  197.         if(pCtlData->lSplit  > CELL_TOP_LIMIT)
  198.             pCtlData->lSplit = CELL_TOP_LIMIT;
  199.  
  200.         if(pCtlData->lSplit  < CELL_BOTTOM_LIMIT)
  201.             pCtlData->lSplit = CELL_BOTTOM_LIMIT;
  202.  
  203.         WinSendMsg(hwnd, WM_UPDATEFRAME, 0, 0);
  204.     }
  205.  
  206.     return pCtlData->lSplit;
  207. }
  208.  
  209. LONG GetSplitType(HWND hwnd, LONG lID)
  210. {
  211.     CellCtlData* pCtlData = 0;
  212.  
  213.     hwnd = CellWindowFromID(hwnd, lID);
  214.  
  215.     if(!hwnd)
  216.         return 0;
  217.  
  218.     pCtlData = (CellCtlData *)WinQueryWindowULong(hwnd, QWL_USER);
  219.  
  220.     if(!pCtlData)
  221.         return 0;
  222.  
  223.     return (pCtlData->lType & (CELL_VSPLIT | CELL_HSPLIT));
  224. }
  225.  
  226. void SetSplitType(HWND hwnd, LONG lID, LONG lNewSplit)
  227. {
  228.     CellCtlData* pCtlData = 0;
  229.  
  230.     lNewSplit &= (CELL_VSPLIT | CELL_HSPLIT);
  231.  
  232.     if((lNewSplit != CELL_VSPLIT) && (lNewSplit != CELL_HSPLIT))
  233.         return;
  234.  
  235.     hwnd = CellWindowFromID(hwnd, lID);
  236.  
  237.     if(!hwnd)
  238.         return;
  239.  
  240.     pCtlData = (CellCtlData *)WinQueryWindowULong(hwnd, QWL_USER);
  241.  
  242.     if(!pCtlData)
  243.         return;
  244.  
  245.     pCtlData->lType &= ~(CELL_VSPLIT | CELL_HSPLIT);
  246.     pCtlData->lType |= lNewSplit;
  247. }
  248.  
  249. /* Function: CountControls
  250. ** Abstract: calculates number of additional controls in cell window
  251. */
  252.  
  253. USHORT CountControls(CellCtlData * pCtlData)
  254. {
  255.     USHORT itemCount = 0;
  256.     CellTb *pCellTb = 0;
  257.  
  258.     if(pCtlData->hwndPanel1 && !(pCtlData->lType & CELL_HIDE_1))
  259.         itemCount++;
  260.  
  261.     if(pCtlData->hwndPanel2 && !(pCtlData->lType & CELL_HIDE_2))
  262.         itemCount++;
  263.  
  264.     pCellTb = pCtlData->pCellTb;
  265.  
  266.     while(pCellTb)
  267.     {
  268.         LONG lFlags = (LONG)WinSendMsg(pCellTb->hWnd,
  269.                                        TKM_QUERY_FLAGS, 0, 0);
  270.         if(lFlags & TB_ATTACHED)
  271.             itemCount++;
  272.  
  273.         pCellTb = pCellTb->pNext;
  274.     }
  275.  
  276.     return itemCount;
  277. }
  278.  
  279. /* Function: CellProc
  280. ** Abstract: Subclass procedure for frame window
  281. */
  282.  
  283. MRESULT EXPENTRY CellProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  284. {
  285.     CellCtlData* pCtlData = 0;
  286.     CellTb *pCellTb = 0;
  287.     USHORT itemCount;
  288.  
  289.     pCtlData = (CellCtlData *)WinQueryWindowULong(hwnd, QWL_USER);
  290.  
  291.     if(!pCtlData)
  292.     {
  293.         return 0;
  294.     }
  295.     switch(msg)
  296.     {
  297.         case WM_ADJUSTWINDOWPOS:
  298.             {
  299.                 HWND hwndBehind;
  300.                 PSWP pSwp;
  301.  
  302.                 pCellTb = pCtlData->pCellTb;
  303.                 pSwp = (PSWP)mp1;
  304.  
  305.                 if(!(pSwp->fl & SWP_ZORDER) || !pCellTb)
  306.                    break;
  307.  
  308.                 hwndBehind = pSwp->hwndInsertBehind;
  309.  
  310.                 while(pCellTb)
  311.                 {
  312.                     LONG lFlags = (LONG)WinSendMsg(pCellTb->hWnd,
  313.                                                    TKM_QUERY_FLAGS, 0, 0);
  314.                     if(!(lFlags & TB_ATTACHED))
  315.                     {
  316.  
  317.                         WinSetWindowPos (pCellTb->hWnd,
  318.                                          hwndBehind,
  319.                                          0, 0, 0, 0, SWP_ZORDER);
  320.  
  321.                         hwndBehind = pCellTb->hWnd;
  322.                     }
  323.  
  324.                     pCellTb = pCellTb->pNext;
  325.                 }
  326.                 pSwp->hwndInsertBehind = hwndBehind;
  327.             }
  328.             break;
  329.  
  330.         case TKM_SEARCH_PARENT:
  331.             {
  332.                 HWND hwndRC;
  333.  
  334.                 if(WinQueryWindowUShort(hwnd, QWS_ID) == (ULONG)mp1)
  335.                     return MRFROMSHORT(FALSE);
  336.  
  337.                 if(WinQueryWindowUShort(pCtlData->hwndPanel1, QWS_ID)
  338.                     == (ULONG)mp1)
  339.                     return (MPARAM)hwnd;
  340.  
  341.                 hwndRC = (HWND)WinSendMsg(pCtlData->hwndPanel1,
  342.                                           TKM_SEARCH_PARENT,
  343.                                           mp1, 0);
  344.                 if(hwndRC)
  345.                     return (MPARAM)hwndRC;
  346.  
  347.                 if(WinQueryWindowUShort(pCtlData->hwndPanel2, QWS_ID)
  348.                     == (ULONG)mp1)
  349.                     return (MPARAM)hwnd;
  350.  
  351.                 hwndRC = (HWND)WinSendMsg(pCtlData->hwndPanel2,
  352.                                           TKM_SEARCH_PARENT,
  353.                                           mp1, 0);
  354.                 if(hwndRC)
  355.                     return (MPARAM)hwndRC;
  356.  
  357.             }
  358.             return MRFROMSHORT(FALSE);
  359.  
  360.         case TKM_SEARCH_ID:
  361.             {
  362.                 HWND hwndRC;
  363.                 pCellTb = pCtlData->pCellTb;
  364.  
  365.                 while(pCellTb)
  366.                 {
  367.                     if(WinQueryWindowUShort(pCellTb->hWnd, QWS_ID)
  368.                         == (ULONG)mp1)
  369.                         return (MPARAM)pCellTb->hWnd;
  370.  
  371.                     hwndRC = (HWND)WinSendMsg(pCellTb->hWnd,
  372.                                               TKM_SEARCH_ID,
  373.                                               mp1, 0);
  374.  
  375.                     if(hwndRC)
  376.                         return (MPARAM)hwndRC;
  377.  
  378.                     pCellTb = pCellTb->pNext;
  379.                 }
  380.  
  381.                 if(WinQueryWindowUShort(hwnd, QWS_ID) == (ULONG)mp1)
  382.                     return (MPARAM)hwnd;
  383.  
  384.                 if(WinQueryWindowUShort(pCtlData->hwndPanel1, QWS_ID)
  385.                     == (ULONG)mp1)
  386.                     return (MPARAM)pCtlData->hwndPanel1;
  387.  
  388.                 hwndRC = (HWND)WinSendMsg(pCtlData->hwndPanel1,
  389.                                           TKM_SEARCH_ID,
  390.                                           mp1, 0);
  391.                 if(hwndRC)
  392.                     return (MPARAM)hwndRC;
  393.  
  394.                 if(WinQueryWindowUShort(pCtlData->hwndPanel2, QWS_ID)
  395.                     == (ULONG)mp1)
  396.                     return (MPARAM)pCtlData->hwndPanel2;
  397.  
  398.                 hwndRC = (HWND)WinSendMsg(pCtlData->hwndPanel2,
  399.                                           TKM_SEARCH_ID,
  400.                                           mp1, 0);
  401.                 if(hwndRC)
  402.                     return (MPARAM)hwndRC;
  403.  
  404.             }
  405.             return MRFROMSHORT(FALSE);
  406.  
  407.         case WM_QUERYFRAMECTLCOUNT:
  408.             {
  409.                 itemCount = (USHORT)(pCtlData->pOldProc(hwnd, msg, mp1, mp2));
  410.                 itemCount += CountControls(pCtlData);
  411.             }
  412.             return MRFROMSHORT(itemCount);
  413.  
  414.         case WM_FORMATFRAME:
  415.             {
  416.                 PSWP   pSWP     = 0;
  417.                 USHORT usClient = 0;
  418.                 USHORT itemCount2;
  419.                 SWP    swp;
  420.                 HWND   hClient = HWND_TOP;
  421.  
  422.                 itemCount  = (USHORT)(pCtlData->pOldProc(hwnd, msg, mp1, mp2));
  423.                 itemCount2 = CountControls(pCtlData);
  424.  
  425.                 if(!itemCount2 || itemCount < 1)
  426.                     return MRFROMSHORT(itemCount);
  427.  
  428.                 pSWP = (PSWP)PVOIDFROMMP(mp1);
  429.  
  430.                 usClient = itemCount - 1;
  431.  
  432.                 hClient  = pSWP[usClient].hwnd;
  433.  
  434.                 /*
  435.                 ** Cutting client window.
  436.                 ** If there are any attached toolbars, cut client window
  437.                 ** regarding to attachment type
  438.                 */
  439.  
  440.                 /* Toolbars attached to top and bottom sides */
  441.  
  442.                 pCellTb = pCtlData->pCellTb;
  443.  
  444.                 while(pCellTb)
  445.                 {
  446.                     POINTL ptlSize;
  447.                     LONG lFlags = (LONG)WinSendMsg(pCellTb->hWnd,
  448.                                                    TKM_QUERY_FLAGS, 0, 0);
  449.  
  450.                     if(!(lFlags & TB_ATTACHED))
  451.                     {
  452.                         pCellTb = pCellTb->pNext;
  453.                         continue;
  454.                     }
  455.  
  456.                     RecalcTbDimensions(pCellTb->hWnd, &ptlSize);
  457.  
  458.                     switch(lFlags & TB_ATTACHED)
  459.                     {
  460.                         case TB_ATTACHED_TP:
  461.                             pSWP[itemCount].x    = pSWP[usClient].x;
  462.                             pSWP[itemCount].y    = pSWP[usClient].y +
  463.                                                    pSWP[usClient].cy - ptlSize.y;
  464.                             pSWP[itemCount].cx   = pSWP[usClient].cx;
  465.                             pSWP[itemCount].cy   = ptlSize.y;
  466.                             pSWP[itemCount].fl   = SWP_SIZE |
  467.                                                    SWP_MOVE |
  468.                                                    SWP_SHOW;
  469.  
  470.                             pSWP[itemCount].hwnd = pCellTb->hWnd;
  471.                             pSWP[itemCount].hwndInsertBehind = hClient;
  472.                             hClient = pSWP[itemCount].hwnd;
  473.  
  474.                             pSWP[usClient].cy -= ptlSize.y;
  475.                             itemCount++;
  476.                             break;
  477.  
  478.                         case TB_ATTACHED_BT:
  479.                             pSWP[itemCount].x    = pSWP[usClient].x;
  480.                             pSWP[itemCount].y    = pSWP[usClient].y;
  481.                             pSWP[itemCount].cx   = pSWP[usClient].cx;
  482.                             pSWP[itemCount].cy   = ptlSize.y;
  483.                             pSWP[itemCount].fl   = SWP_SIZE | SWP_MOVE | SWP_SHOW;
  484.  
  485.                             pSWP[itemCount].hwnd = pCellTb->hWnd;
  486.                             pSWP[itemCount].hwndInsertBehind = hClient;
  487.                             hClient = pSWP[itemCount].hwnd;
  488.  
  489.                             pSWP[usClient].cy -= ptlSize.y;
  490.                             pSWP[usClient].y  += ptlSize.y;
  491.                             itemCount++;
  492.                             break;
  493.                     }
  494.                     pCellTb = pCellTb->pNext;
  495.                 }
  496.  
  497.                 /*Toolbars attached to left and right sides*/
  498.  
  499.                 pCellTb = pCtlData->pCellTb;
  500.  
  501.                 while(pCellTb)
  502.                 {
  503.                     POINTL ptlSize;
  504.                     LONG lFlags = (LONG)WinSendMsg(pCellTb->hWnd,
  505.                                                    TKM_QUERY_FLAGS, 0, 0);
  506.  
  507.                     if(!(lFlags & TB_ATTACHED))
  508.                     {
  509.                         pCellTb = pCellTb->pNext;
  510.                         continue;
  511.                     }
  512.  
  513.                     RecalcTbDimensions(pCellTb->hWnd, &ptlSize);
  514.  
  515.                     switch(lFlags & TB_ATTACHED)
  516.                     {
  517.                         case TB_ATTACHED_LT:
  518.                             pSWP[itemCount].x    = pSWP[usClient].x;
  519.                             pSWP[itemCount].y    = pSWP[usClient].y;
  520.                             pSWP[itemCount].cx   = ptlSize.x;
  521.                             pSWP[itemCount].cy   = pSWP[usClient].cy;
  522.                             pSWP[itemCount].fl   = SWP_SIZE | SWP_MOVE | SWP_SHOW;
  523.                             pSWP[itemCount].hwnd = pCellTb->hWnd;
  524.                             pSWP[itemCount].hwndInsertBehind = hClient;
  525.                             hClient = pSWP[itemCount].hwnd;
  526.  
  527.                             pSWP[usClient].cx -= ptlSize.x;
  528.                             pSWP[usClient].x  += ptlSize.x;
  529.                             itemCount++;
  530.                             break;
  531.  
  532.                         case TB_ATTACHED_RT:
  533.                             pSWP[itemCount].x    = pSWP[usClient].x +
  534.                                                    pSWP[usClient].cx - ptlSize.x;
  535.                             pSWP[itemCount].y    = pSWP[usClient].y;
  536.                             pSWP[itemCount].cx   = ptlSize.x;
  537.                             pSWP[itemCount].cy   = pSWP[usClient].cy;
  538.                             pSWP[itemCount].fl   = SWP_SIZE | SWP_MOVE | SWP_SHOW;
  539.                             pSWP[itemCount].hwnd = pCellTb->hWnd;
  540.                             pSWP[itemCount].hwndInsertBehind = hClient;
  541.                             hClient = pSWP[itemCount].hwnd;
  542.  
  543.                             pSWP[usClient].cx -= ptlSize.x;
  544.                             itemCount++;
  545.                             break;
  546.                     }
  547.                     pCellTb = pCellTb->pNext;
  548.                 }
  549.  
  550.                 /*
  551.                 ** Placing panels.
  552.                 ** Remember client rect for future use
  553.                 ** They will save time when we start moving splitbar
  554.                 */
  555.  
  556.                 pCtlData->rclBnd.xLeft   = pSWP[usClient].x;
  557.                 pCtlData->rclBnd.xRight  = pSWP[usClient].x + pSWP[usClient].cx;
  558.                 pCtlData->rclBnd.yTop    = pSWP[usClient].y + pSWP[usClient].cy;
  559.                 pCtlData->rclBnd.yBottom = pSWP[usClient].y;
  560.  
  561.                 if(!pCtlData->hwndPanel1 || !pCtlData->hwndPanel2 ||
  562.                    (pCtlData->lType & CELL_HIDE))
  563.                 {
  564.                     /*
  565.                     **single subwindow;
  566.                     **In this case we don't need a client window,
  567.                     **because of lack of splitbar.
  568.                     **Just copy all data from pSWP[usClient]
  569.                     **and replace some part of it
  570.                     */
  571.  
  572.                     pSWP[itemCount]     = pSWP[usClient];
  573.                     pSWP[itemCount].fl |= SWP_MOVE | SWP_SIZE;
  574.                     pSWP[itemCount].hwndInsertBehind = HWND_TOP;
  575.                     pSWP[usClient].cy = 0;
  576.  
  577.                     pSWP[itemCount].hwnd = 0;
  578.  
  579.                     if(pCtlData->hwndPanel1 && !(pCtlData->lType & CELL_HIDE_1))
  580.                         pSWP[itemCount].hwnd = pCtlData->hwndPanel1;
  581.  
  582.                     if(pCtlData->hwndPanel2 && !(pCtlData->lType & CELL_HIDE_2))
  583.                         pSWP[itemCount].hwnd = pCtlData->hwndPanel2;
  584.  
  585.                     /* Increase number of controls */
  586.  
  587.                     if(pSWP[itemCount].hwnd)
  588.                     {
  589.                         pSWP[itemCount].hwndInsertBehind = hClient;
  590.                         hClient = pSWP[itemCount].hwnd;
  591.                         itemCount++;
  592.                     }
  593.                 }
  594.                 else
  595.                 {
  596.                     USHORT usPanel1 = itemCount;
  597.                     USHORT usPanel2 = itemCount + 1;
  598.                     USHORT usWidth1 = 0;
  599.                     USHORT usWidth2 = 0;
  600.  
  601.                     /* Just like case of one panel */
  602.  
  603.                     pSWP[usPanel1] = pSWP[usClient];
  604.                     pSWP[usPanel2] = pSWP[usClient];
  605.  
  606.                     pSWP[usPanel1].fl |= SWP_MOVE | SWP_SIZE;
  607.                     pSWP[usPanel2].fl |= SWP_MOVE | SWP_SIZE;
  608.  
  609.                     pSWP[usPanel1].hwndInsertBehind = hClient;
  610.                     pSWP[usPanel2].hwndInsertBehind = pCtlData->hwndPanel1;
  611.  
  612.                     pSWP[usPanel1].hwnd = pCtlData->hwndPanel1;
  613.                     pSWP[usPanel2].hwnd = pCtlData->hwndPanel2;
  614.  
  615.                     hClient = pCtlData->hwndPanel2;
  616.  
  617.                     if(pCtlData->lType & CELL_VSPLIT)
  618.                     {
  619.                         if((pCtlData->lType & CELL_FIXED) &&
  620.                            (pCtlData->lType & (CELL_SIZE1 | CELL_SIZE2)) &&
  621.                            (pCtlData->lSize > 0))
  622.                         {
  623.                             /* Case of fixed panel with exact size */
  624.  
  625.                             if(pCtlData->lType & CELL_SIZE1)
  626.                             {
  627.                                 usWidth1 = pCtlData->lSize;
  628.                                 usWidth2 = pSWP[usClient].cx - usWidth1;
  629.                             }
  630.                             else
  631.                             {
  632.                                 usWidth2 = pCtlData->lSize;
  633.                                 usWidth1 = pSWP[usClient].cx - usWidth2;
  634.                             }
  635.                         }
  636.                         else
  637.                         {
  638.                             usWidth1 = (pSWP[usClient].cx * pCtlData->lSplit)
  639.                                         / 100;
  640.                             usWidth2 = pSWP[usClient].cx - usWidth1;
  641.                         }
  642.  
  643.                         if(pCtlData->lType & CELL_SPLITBAR)
  644.                         {
  645.                             if(!(pCtlData->lType & CELL_SIZE1))
  646.                                 usWidth2 -= SPLITBAR_WIDTH;
  647.                             else
  648.                                 usWidth1 -= SPLITBAR_WIDTH;
  649.  
  650.                             pSWP[usClient].cx = SPLITBAR_WIDTH;
  651.                             pSWP[usClient].x  = pSWP[usClient].x + usWidth1;
  652.                         }
  653.                         else
  654.                         {
  655.                             pSWP[usClient].cx = 0;
  656.                             pSWP[usClient].cy = 0;
  657.                         }
  658.  
  659.                         pSWP[usPanel1].cx  = usWidth1;
  660.                         pSWP[usPanel2].x  += usWidth1 + pSWP[usClient].cx;
  661.                         pSWP[usPanel2].cx  = usWidth2;
  662.                     }
  663.                     else
  664.                     {
  665.                         if((pCtlData->lType & CELL_FIXED) &&
  666.                            (pCtlData->lType & (CELL_SIZE1 | CELL_SIZE2)) &&
  667.                            (pCtlData->lSize > 0))
  668.                         {
  669.                             /* Case of fixed panel with exact size */
  670.  
  671.                             if(pCtlData->lType & CELL_SIZE1)
  672.                             {
  673.                                 usWidth1 = pCtlData->lSize;
  674.                                 usWidth2 = pSWP[usClient].cy - usWidth1;
  675.                             }
  676.                             else
  677.                             {
  678.                                 usWidth2 = pCtlData->lSize;
  679.                                 usWidth1 = pSWP[usClient].cy - usWidth2;
  680.                             }
  681.                         }
  682.                         else
  683.                         {
  684.                             usWidth1 = (pSWP[usClient].cy * pCtlData->lSplit)
  685.                                        / 100;
  686.                             usWidth2 = pSWP[usClient].cy - usWidth1;
  687.                         }
  688.  
  689.                         if(pCtlData->lType & CELL_SPLITBAR)
  690.                         {
  691.                             if(!(pCtlData->lType & CELL_SIZE1))
  692.                                 usWidth2 -= SPLITBAR_WIDTH;
  693.                             else
  694.                                 usWidth1 -= SPLITBAR_WIDTH;
  695.                             pSWP[usClient].cy = SPLITBAR_WIDTH;
  696.                             pSWP[usClient].y  = pSWP[usClient].y + usWidth1;
  697.                         }
  698.                         else
  699.                         {
  700.                             pSWP[usClient].cx = 0;
  701.                             pSWP[usClient].cy = 0;
  702.                         }
  703.  
  704.                         pSWP[usPanel1].cy  = usWidth1;
  705.                         pSWP[usPanel2].y  += usWidth1 + pSWP[usClient].cy;
  706.                         pSWP[usPanel2].cy  = usWidth2;
  707.                     }
  708.  
  709.                     itemCount += 2;
  710.                 }
  711.             }
  712.             return MRFROMSHORT(itemCount);
  713.     }
  714.     return pCtlData->pOldProc(hwnd, msg, mp1, mp2);
  715. }
  716.  
  717. /* Function: CellClientProc
  718. ** Abstract: Window procedure for Cell Client Window Class (splitbar)
  719. */
  720.  
  721. MRESULT EXPENTRY CellClientProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  722. {
  723.     HWND hwndFrame = 0;
  724.     CellCtlData *pCtlData = 0;
  725.  
  726.     hwndFrame = WinQueryWindow(hwnd, QW_PARENT);
  727.     if(hwndFrame)
  728.         pCtlData = (CellCtlData *)WinQueryWindowULong(hwndFrame, QWL_USER);
  729.  
  730.     switch (msg)
  731.     {
  732.         case WM_ACTIVATE:
  733.         case WM_SETFOCUS:
  734.             return (MRESULT)(FALSE);
  735.  
  736.         case WM_PAINT:
  737.             {
  738.                 HPS hpsPaint;
  739.                 RECTL rclPaint;
  740.                 POINTL ptlStart[SPLITBAR_WIDTH];
  741.                 POINTL ptlEnd[SPLITBAR_WIDTH];
  742.                 PLONG pColorTable;
  743.                 USHORT i;
  744.  
  745.                 hpsPaint = WinBeginPaint(hwnd, 0, 0);
  746.                 WinQueryWindowRect(hwnd, &rclPaint);
  747.  
  748.                 if(pCtlData->lType & CELL_VSPLIT)
  749.                 {
  750.                     for(i = 0; i < SPLITBAR_WIDTH; i++)
  751.                     {
  752.                         ptlStart[i].x = rclPaint.xLeft + i;
  753.                         ptlStart[i].y = rclPaint.yTop;
  754.  
  755.                         ptlEnd[i].x = rclPaint.xLeft + i;
  756.                         ptlEnd[i].y = rclPaint.yBottom;
  757.                     }
  758.                     pColorTable = (pCtlData->lType & CELL_FIXED)
  759.                                    ? lColor
  760.                                    : lColor2;
  761.                 }
  762.                 else
  763.                 {
  764.                     for(i = 0; i < SPLITBAR_WIDTH; i++)
  765.                     {
  766.                         ptlStart[i].x = rclPaint.xLeft;
  767.                         ptlStart[i].y = rclPaint.yBottom + i;
  768.  
  769.                         ptlEnd[i].x = rclPaint.xRight;
  770.                         ptlEnd[i].y = rclPaint.yBottom + i;
  771.                     }
  772.                     pColorTable = (pCtlData->lType & CELL_FIXED)
  773.                                    ? lColor2
  774.                                    : lColor;
  775.                 }
  776.  
  777.                 for(i = 0; i < SPLITBAR_WIDTH; i++)
  778.                 {
  779.                     GpiSetColor( hpsPaint, pColorTable[i]);
  780.                     GpiMove(hpsPaint, &ptlStart[i]);
  781.                     GpiLine(hpsPaint, &ptlEnd[i]);
  782.                 }
  783.                 WinEndPaint(hpsPaint);
  784.             }
  785.             return MRFROMSHORT(FALSE);
  786.  
  787.         case WM_MOUSEMOVE:
  788.             {
  789.                 if(pCtlData->lType & CELL_FIXED)
  790.                     break;
  791.  
  792.                 if(pCtlData->lType & CELL_VSPLIT)
  793.                     WinSetPointer(HWND_DESKTOP,
  794.                                   WinQuerySysPointer(HWND_DESKTOP,
  795.                                                      SPTR_SIZEWE,
  796.                                                      FALSE));
  797.                 else
  798.                     WinSetPointer(HWND_DESKTOP,
  799.                                   WinQuerySysPointer(HWND_DESKTOP,
  800.                                                      SPTR_SIZENS,
  801.                                                      FALSE));
  802.             }
  803.             return MRFROMSHORT(FALSE);
  804.  
  805.         case WM_BUTTON1DOWN:
  806.             {
  807.                 APIRET rc;
  808.                 RECTL  rclFrame;
  809.                 RECTL  rclBounds;
  810.  
  811.                 if(pCtlData->lType & CELL_FIXED)
  812.                     break;
  813.  
  814.                 WinQueryWindowRect(hwnd, &rclFrame);
  815.  
  816.                 rclBounds = pCtlData->rclBnd;
  817.  
  818.                 WinMapWindowPoints(hwndFrame, HWND_DESKTOP,
  819.                                    (PPOINTL)&rclBounds, 2);
  820.  
  821.                 rc = TrackRectangle(hwnd, &rclFrame, &rclBounds);
  822.  
  823.                 if(rc == TRUE)
  824.                 {
  825.                     USHORT usNewRB;
  826.                     USHORT usSize;
  827.  
  828.                     if(pCtlData->lType & CELL_VSPLIT)
  829.                     {
  830.                         usNewRB = rclFrame.xLeft
  831.                                 - rclBounds.xLeft;
  832.                         usSize  = rclBounds.xRight
  833.                                 - rclBounds.xLeft;
  834.                     }
  835.                     else
  836.                     {
  837.                         usNewRB = rclFrame.yBottom
  838.                                 - rclBounds.yBottom;
  839.                         usSize  = rclBounds.yTop
  840.                                 - rclBounds.yBottom;
  841.                     }
  842.  
  843.                     pCtlData->lSplit = (usNewRB * 100)/usSize;
  844.                     if(pCtlData->lSplit  > CELL_TOP_LIMIT)
  845.                         pCtlData->lSplit = CELL_TOP_LIMIT;
  846.  
  847.                     if(pCtlData->lSplit  < CELL_BOTTOM_LIMIT)
  848.                         pCtlData->lSplit = CELL_BOTTOM_LIMIT;
  849.  
  850.                     WinSendMsg(hwndFrame, WM_UPDATEFRAME, 0, 0);
  851.                 }
  852.             }
  853.             return MRFROMSHORT(FALSE);
  854.     }
  855.     return WinDefWindowProc(hwnd, msg, mp1, mp2);
  856. }
  857.  
  858. /* Function: CreateCell
  859. ** Abstract: Creates a subwindows tree for a given CellDef
  860. ** Note: If hWndOwner == NULLHANDLE, and first CellDef is frame,
  861. **       all subwindows will have this frame window as Owner.
  862. */
  863.  
  864. HWND CreateCell(CellDef* pCell, HWND hWndParent, HWND hWndOwner)
  865. {
  866.     HWND hwndFrame        = NULLHANDLE;
  867.     CellCtlData* pCtlData = 0;
  868.     WindowCellCtlData * pWCtlData = 0;
  869.  
  870.     if(!pCell)
  871.         return hwndFrame;
  872.  
  873.     switch(pCell->lType & (CELL_VSPLIT | CELL_HSPLIT | CELL_WINDOW))
  874.     {
  875.         case CELL_WINDOW:
  876.             hwndFrame = WinCreateWindow(hWndParent,
  877.                                         pCell->pszClass,
  878.                                         pCell->pszName,
  879.                                         pCell->ulStyle,
  880.                                         0, 0, 0, 0,
  881.                                         hWndOwner,
  882.                                         HWND_TOP,
  883.                                         pCell->ulID,
  884.                                         NULL,
  885.                                         NULL);
  886.  
  887.             if(pCell->pClassProc && hwndFrame)
  888.             {
  889.                 pWCtlData = (WindowCellCtlData *)
  890.                              malloc(sizeof(WindowCellCtlData));
  891.                 if(!pWCtlData)
  892.                     return hwndFrame;
  893.  
  894.                 memset(pWCtlData, 0, sizeof(WindowCellCtlData));
  895.                 pWCtlData->pOldProc = WinSubclassWindow(hwndFrame,
  896.                                                         pCell->pClassProc);
  897.                 WinSetWindowULong(hwndFrame, QWL_USER, (ULONG)pWCtlData);
  898.             }
  899.             break;
  900.  
  901.         case CELL_HSPLIT:
  902.         case CELL_VSPLIT:
  903.  
  904.             pCtlData = (CellCtlData *)malloc(sizeof(CellCtlData));
  905.             if(!pCtlData)
  906.                 return hwndFrame;
  907.  
  908.             memset(pCtlData, 0, sizeof(CellCtlData));
  909.  
  910.             pCtlData->lType = pCell->lType & CELL_SPLIT_MASK;
  911.             pCtlData->lSize = (pCell->lType & (CELL_SIZE1
  912.                                                | CELL_SIZE2
  913.                                                | CELL_FIXED))
  914.                                 ? pCell->lSize
  915.                                 : 0;
  916.  
  917.             pCtlData->lSplit = 50;
  918.  
  919.             switch(pCell->lType & CELL_SPLIT_REL)
  920.             {
  921.                 case CELL_SPLIT10x90: pCtlData->lSplit = 10; break;
  922.                 case CELL_SPLIT20x80: pCtlData->lSplit = 20; break;
  923.                 case CELL_SPLIT30x70: pCtlData->lSplit = 30; break;
  924.                 case CELL_SPLIT40x60: pCtlData->lSplit = 40; break;
  925.                 case CELL_SPLIT50x50: pCtlData->lSplit = 50; break;
  926.                 case CELL_SPLIT60x40: pCtlData->lSplit = 60; break;
  927.                 case CELL_SPLIT70x30: pCtlData->lSplit = 70; break;
  928.                 case CELL_SPLIT80x20: pCtlData->lSplit = 80; break;
  929.                 case CELL_SPLIT90x10: pCtlData->lSplit = 90; break;
  930.             }
  931.  
  932.             hwndFrame = WinCreateStdWindow(hWndParent,
  933.                                            WS_VISIBLE,
  934.                                            &pCell->ulStyle,
  935.                                            CELL_CLIENT,
  936.                                            "",
  937.                                            0L, 0,
  938.                                            pCell->ulID,
  939.                                            &pCtlData->hwndSplitbar);
  940.  
  941.             WinSetOwner(hwndFrame, hWndOwner);
  942.  
  943.             if(pCell->pClassProc)
  944.                 pCtlData->pOldProc = WinSubclassWindow(hwndFrame,
  945.                                                        pCell->pClassProc);
  946.             else
  947.                 pCtlData->pOldProc = WinSubclassWindow(hwndFrame, CellProc);
  948.  
  949.             if(pCell->pClientClassProc)
  950.             {
  951.                 pWCtlData = (WindowCellCtlData *)
  952.                              malloc(sizeof(WindowCellCtlData));
  953.                 if(!pWCtlData)
  954.                     return hwndFrame;
  955.  
  956.                 memset(pWCtlData, 0, sizeof(WindowCellCtlData));
  957.  
  958.                 pWCtlData->pOldProc = WinSubclassWindow(pCtlData->hwndSplitbar,
  959.                                                        pCell->pClientClassProc);
  960.                 WinSetWindowULong(pCtlData->hwndSplitbar,
  961.                                   QWL_USER,
  962.                                   (ULONG)pWCtlData);
  963.             }
  964.  
  965.             if(!hWndOwner)
  966.                 hWndOwner = hwndFrame;
  967.             else
  968.                 WinSetOwner(pCtlData->hwndSplitbar, hWndOwner);
  969.  
  970.             pCtlData->hwndPanel1 = CreateCell(pCell->pPanel1,
  971.                                               hwndFrame,
  972.                                               hWndOwner);
  973.             pCtlData->hwndPanel2 = CreateCell(pCell->pPanel2,
  974.                                               hwndFrame,
  975.                                               hWndOwner);
  976.  
  977.             WinSetWindowULong(hwndFrame, QWL_USER, (ULONG)pCtlData);
  978.             break;
  979.     }
  980.  
  981.     return hwndFrame;
  982. }
  983.  
  984. /*****************************************************************************
  985. ** Toolbar implementation
  986. */
  987.  
  988. /* Function: CreateTb
  989. ** Abstract: Creates Toolbar for a gived TbDef
  990. */
  991.  
  992. HWND CreateTb(TbDef* pTb, HWND hWndParent, HWND hWndOwner)
  993. {
  994.     SWP   swp;
  995.     HWND  hwndClient;
  996.     HWND  hwndTb = NULLHANDLE;
  997.     LONG  lCount;
  998.     POINTL ptlSize;
  999.     POINTL ptlFSize;
  1000.     ULONG  flCreate;
  1001.     TbCtlData  *pTbCtlData;
  1002.     TbItemData *pTbItemData;
  1003.  
  1004.     if(!pTb)
  1005.         return hwndTb;
  1006.  
  1007.     for(lCount = 0; pTb->tbItems[lCount]; )
  1008.         lCount++;
  1009.  
  1010.     pTbCtlData  = (TbCtlData *)malloc(sizeof(TbCtlData) +
  1011.                                       sizeof(HWND) * lCount);
  1012.  
  1013.     if(!pTbCtlData)
  1014.         return hwndTb;
  1015.  
  1016.     pTbItemData = (TbItemData *)malloc(sizeof(TbItemData) * lCount);
  1017.  
  1018.     if(!pTbItemData)
  1019.     {
  1020.         free(pTbCtlData);
  1021.         return hwndTb;
  1022.     }
  1023.  
  1024.     memset(pTbCtlData, 0, sizeof(TbCtlData) +
  1025.                           sizeof(HWND) * lCount);
  1026.  
  1027.     memset(pTbItemData, 0, sizeof(TbItemData) * lCount);
  1028.  
  1029.     pTbCtlData->lCount  = lCount;
  1030.     pTbCtlData->bBubble = (pTb->lType & TB_BUBBLE) ? 1:0;
  1031.  
  1032.     pTb->lType &= TB_ALLOWED;
  1033.  
  1034.     /*
  1035.     **Some checks:
  1036.     ** if toolbar attached, they should be properly
  1037.     ** oriented. I.e. toolbar attached to top or
  1038.     ** bottom, can't be vertical.
  1039.     */
  1040.  
  1041.     if(pTb->lType & (TB_ATTACHED_TP | TB_ATTACHED_BT))
  1042.         pTb->lType &= ~TB_VERTICAL;
  1043.  
  1044.     pTbCtlData->lState = pTb->lType;
  1045.     pTbCtlData->hwndParent = hWndParent;
  1046.  
  1047.     if(!(pTb->lType & TB_ATTACHED))
  1048.         hWndParent = HWND_DESKTOP;
  1049.  
  1050.     if(pTb->lType & TB_ATTACHED)
  1051.         flCreate = FCF_BORDER | FCF_NOBYTEALIGN;
  1052.     else
  1053.         flCreate = FCF_DLGBORDER | FCF_NOBYTEALIGN;
  1054.  
  1055.     hwndTb = WinCreateStdWindow(hWndParent,
  1056.                                 WS_CLIPCHILDREN |
  1057.                                 WS_CLIPSIBLINGS |
  1058.                                 WS_PARENTCLIP |
  1059.                                 0,
  1060.                                 &flCreate,
  1061.                                 TB_CLIENT,
  1062.                                 "",
  1063.                                 0L, 0,
  1064.                                 pTb->ulID,
  1065.                                 &hwndClient);
  1066.     if(!hwndTb)
  1067.     {
  1068.         free(pTbCtlData);
  1069.         free(pTbItemData);
  1070.         return hwndTb;
  1071.     }
  1072.  
  1073.     ptlSize.x = (pTbCtlData->lState & TB_VERTICAL) ? 0 : HAND_SIZE;
  1074.     ptlSize.y = (pTbCtlData->lState & TB_VERTICAL) ? HAND_SIZE : 0;
  1075.  
  1076.     for(lCount = 0; lCount < pTbCtlData->lCount; lCount++)
  1077.     {
  1078.         CHAR cButtText[256];
  1079.  
  1080.         if(pTb->tbItems[lCount] == TB_SEPARATOR)
  1081.             pTbCtlData->hItems[lCount] =
  1082.                 WinCreateWindow(hwndTb,
  1083.                                 TB_SEPCLASS,
  1084.                                 "",
  1085.                                 0,
  1086.                                 0, 0, TB_SEP_SIZE, TB_SEP_SIZE,
  1087.                                 hwndTb,
  1088.                                 HWND_TOP,
  1089.                                 pTb->tbItems[lCount],
  1090.                                 NULL,
  1091.                                 NULL);
  1092.         else
  1093.         {
  1094.             flCreate = BS_PUSHBUTTON | BS_BITMAP |
  1095.                        BS_AUTOSIZE | BS_NOPOINTERFOCUS;
  1096.  
  1097.             GenResIDStr(cButtText, pTb->tbItems[lCount]);
  1098.  
  1099.             pTbCtlData->hItems[lCount] =
  1100.                                     WinCreateWindow(hwndTb,
  1101.                                                     WC_BUTTON,
  1102.                                                     cButtText,
  1103.                                                     flCreate,
  1104.                                                     -1, -1, -1, -1,
  1105.                                                     hWndOwner,
  1106.                                                     HWND_TOP,
  1107.                                                     pTb->tbItems[lCount],
  1108.                                                     NULL,
  1109.                                                     NULL);
  1110.  
  1111.             pTbItemData[lCount].pOldProc =
  1112.                       WinSubclassWindow(pTbCtlData->hItems[lCount],
  1113.                                         BtProc);
  1114.  
  1115.            WinSetWindowULong(pTbCtlData->hItems[lCount],
  1116.                              QWL_USER,
  1117.                              (ULONG)(&pTbItemData[lCount]));
  1118.         }
  1119.  
  1120.         WinQueryWindowPos(pTbCtlData->hItems[lCount], &swp);
  1121.  
  1122.         if(pTbCtlData->lState & TB_VERTICAL)
  1123.         {
  1124.             if(swp.cx > ptlSize.x)
  1125.                 ptlSize.x = swp.cx;
  1126.             ptlSize.y += swp.cy;
  1127.         }
  1128.         else
  1129.         {
  1130.             if(swp.cy > ptlSize.y)
  1131.                 ptlSize.y = swp.cy;
  1132.             ptlSize.x += swp.cx;
  1133.         }
  1134.     }
  1135.  
  1136.     /*
  1137.     **Now we have calculated client window size for toolbar
  1138.     **Recalculate them to proper size
  1139.     */
  1140.  
  1141.     WinSendMsg(hwndTb, WM_QUERYBORDERSIZE, MPFROMP(&ptlFSize), 0);
  1142.     ptlSize.x += ptlFSize.x * 2;
  1143.     ptlSize.y += ptlFSize.y * 2;
  1144.  
  1145.     pTbCtlData->pOldProc = WinSubclassWindow(hwndTb, TbProc);
  1146.     WinSetWindowULong(hwndTb, QWL_USER, (ULONG)pTbCtlData);
  1147.  
  1148.     WinQueryWindowPos(hWndOwner, &swp);
  1149.  
  1150.     WinSetWindowPos(hwndTb, 0, swp.x + HAND_SIZE/2, swp.y + HAND_SIZE/2,
  1151.                     ptlSize.x, ptlSize.y, SWP_MOVE | SWP_SIZE | SWP_SHOW);
  1152.  
  1153.     return hwndTb;
  1154. }
  1155.  
  1156. /* Function: BtProc
  1157. ** Abstract: Subclass procedure for buttons
  1158. */
  1159.  
  1160. MRESULT EXPENTRY BtProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1161. {
  1162.     HWND hwndFrame = 0;
  1163.     TbCtlData  *pTbCtlData;
  1164.     TbItemData *pTbItemData;
  1165.  
  1166.     hwndFrame = WinQueryWindow(hwnd, QW_PARENT);
  1167.     pTbCtlData  = (TbCtlData *)WinQueryWindowULong(hwndFrame,
  1168.                                                    QWL_USER);
  1169.  
  1170.     pTbItemData = (TbItemData *)WinQueryWindowULong(hwnd,
  1171.                                                     QWL_USER);
  1172.     switch(msg)
  1173.     {
  1174.         case WM_TIMER:
  1175.             if (pTbCtlData->hwndBubble)
  1176.             {
  1177.                 WinDestroyWindow(pTbCtlData->hwndBubble);
  1178.                 pTbCtlData->hwndBubble = 0;
  1179.                 WinStopTimer(hab, hwnd, 1);
  1180.             }
  1181.             break;
  1182.  
  1183.         case WM_MOUSEMOVE:
  1184.  
  1185.             if(!(pTbCtlData->lState & TB_BUBBLE))
  1186.                 break;
  1187.  
  1188.             if(!pTbCtlData->bBubble)
  1189.                 break;
  1190.  
  1191.             if(WinQueryActiveWindow(HWND_DESKTOP) != hwndFrame &&
  1192.                WinQueryActiveWindow(HWND_DESKTOP) != pTbCtlData->hwndParent)
  1193.             break;
  1194.  
  1195.             if(pTbCtlData->hwndLast == hwnd)
  1196.                 break;
  1197.  
  1198.             if(pTbCtlData->hwndBubble)
  1199.             {
  1200.                 WinDestroyWindow(pTbCtlData->hwndBubble);
  1201.                 pTbCtlData->hwndBubble = 0;
  1202.                 WinStopTimer(hab, pTbCtlData->hwndLast, 1);
  1203.             }
  1204.  
  1205.             if(!pTbCtlData->hwndBubble)
  1206.             {
  1207.                 HWND  hwndBubbleClient;
  1208.                 ULONG ulStyle = FCF_BORDER | FCF_NOBYTEALIGN;
  1209.                 HPS   hpsTemp = 0;
  1210.                 LONG  lHight;
  1211.                 LONG  lWidth;
  1212.                 POINTL txtPointl[TXTBOX_COUNT];
  1213.                 POINTL ptlWork = {0,0};
  1214.                 ULONG ulColor = CLR_PALEGRAY;
  1215.  
  1216.                 pTbCtlData->hwndLast   = hwnd;
  1217.                 pTbCtlData->hwndBubble = WinCreateStdWindow(HWND_DESKTOP,
  1218.                                                             0,
  1219.                                                             &ulStyle,
  1220.                                                             WC_STATIC,
  1221.                                                             "",
  1222.                                                             SS_TEXT |
  1223.                                                             DT_LEFT |
  1224.                                                             DT_VCENTER,
  1225.                                                             NULLHANDLE,
  1226.                                                             TB_BUBBLEID,
  1227.                                                             &hwndBubbleClient);
  1228.  
  1229.                 WinSetPresParam(hwndBubbleClient,
  1230.                                 PP_FONTNAMESIZE,
  1231.                                 sizeof(ppFont),
  1232.                                 ppFont);
  1233.  
  1234.  
  1235.                 WinSetPresParam(hwndBubbleClient,
  1236.                                 PP_BACKGROUNDCOLORINDEX,
  1237.                                 sizeof(ulColor),
  1238.                                 &ulColor);
  1239.  
  1240.                 if(!pTbItemData->cText[0])
  1241.                 {
  1242.                     WinLoadString(hab,
  1243.                                   0,
  1244.                                   WinQueryWindowUShort(hwnd, QWS_ID),
  1245.                                   sizeof(pTbItemData->cText),
  1246.                                   pTbItemData->cText);
  1247.                 }
  1248.  
  1249.                 WinSetWindowText(hwndBubbleClient,
  1250.                                  pTbItemData->cText);
  1251.  
  1252.                 WinMapWindowPoints(hwnd, HWND_DESKTOP, &ptlWork, 1);
  1253.  
  1254.                 hpsTemp = WinGetPS(hwndBubbleClient);
  1255.                 GpiQueryTextBox(hpsTemp,
  1256.                                 strlen(pTbItemData->cText),
  1257.                                 pTbItemData->cText,
  1258.                                 TXTBOX_COUNT,
  1259.                                 txtPointl);
  1260.  
  1261.                 WinReleasePS(hpsTemp);
  1262.  
  1263.                 lWidth = txtPointl[TXTBOX_TOPRIGHT].x -
  1264.                          txtPointl[TXTBOX_TOPLEFT ].x +
  1265.                          WinQuerySysValue(HWND_DESKTOP,
  1266.                                           SV_CYDLGFRAME) * 2;
  1267.  
  1268.                 lHight = txtPointl[TXTBOX_TOPLEFT   ].y -
  1269.                          txtPointl[TXTBOX_BOTTOMLEFT].y +
  1270.                          WinQuerySysValue(HWND_DESKTOP,
  1271.                                           SV_CXDLGFRAME) * 2;
  1272.  
  1273.                 if(!(pTbCtlData->lState & TB_VERTICAL))
  1274.                     ptlWork.y -= lHight;
  1275.                 else
  1276.                 {
  1277.                     RECTL rclButton;
  1278.                     WinQueryWindowRect(hwnd, &rclButton);
  1279.                     ptlWork.x += rclButton.xRight - rclButton.xLeft;
  1280.                 }
  1281.  
  1282.                 WinSetWindowPos(pTbCtlData->hwndBubble,
  1283.                                 HWND_TOP,
  1284.                                 ptlWork.x,
  1285.                                 ptlWork.y,
  1286.                                 lWidth,
  1287.                                 lHight,
  1288.                                 SWP_SIZE | SWP_MOVE | SWP_SHOW);
  1289.  
  1290.                 WinStartTimer(hab, hwnd, 1, 1500);
  1291.             }
  1292.             break;
  1293.     }
  1294.  
  1295.     return pTbItemData->pOldProc(hwnd, msg, mp1, mp2);
  1296. }
  1297.  
  1298. /* Function: TbProc
  1299. ** Abstract: Subclass procedure for toolbar window
  1300. */
  1301.  
  1302. MRESULT EXPENTRY TbProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1303. {
  1304.     TbCtlData* pTbCtlData = 0;
  1305.     USHORT itemCount;
  1306.  
  1307.     pTbCtlData = (TbCtlData *)WinQueryWindowULong(hwnd, QWL_USER);
  1308.  
  1309.     if(!pTbCtlData)
  1310.     {
  1311.         return 0;
  1312.     }
  1313.     switch(msg)
  1314.     {
  1315. /* Internal messages */
  1316.  
  1317.         case TKM_SEARCH_ID:
  1318.             {
  1319.                 LONG lCount;
  1320.  
  1321.                 for(lCount = 0; lCount < pTbCtlData->lCount; lCount++)
  1322.                 {
  1323.                     if(WinQueryWindowUShort(pTbCtlData->hItems[lCount],
  1324.                                             QWS_ID) == (ULONG)mp1)
  1325.                         return (MRESULT)pTbCtlData->hItems[lCount];
  1326.                 }
  1327.             }
  1328.             return MRFROMSHORT(FALSE);
  1329.  
  1330.         case TKM_QUERY_FLAGS:
  1331.             return MRFROMLONG(pTbCtlData->lState);
  1332.  
  1333. /* Standard messages */
  1334.  
  1335.         case WM_QUERYFRAMECTLCOUNT:
  1336.             {
  1337.                 itemCount = (USHORT)(pTbCtlData->pOldProc(hwnd, msg, mp1, mp2));
  1338.                 itemCount += pTbCtlData->lCount;
  1339.             }
  1340.             return MRFROMSHORT(itemCount);
  1341.  
  1342.         case WM_FORMATFRAME:
  1343.             {
  1344.                 PSWP   pSWP      = 0;
  1345.                 USHORT usClient  = 0;
  1346.                 LONG   lOffset = 0;
  1347.                 LONG   lCount;
  1348.                 SWP    swp;
  1349.  
  1350.                 itemCount = (USHORT)(pTbCtlData->pOldProc(hwnd, msg, mp1, mp2));
  1351.  
  1352.                 pSWP = (PSWP)PVOIDFROMMP(mp1);
  1353.  
  1354.                 while(pSWP[usClient].hwnd != WinWindowFromID(hwnd, FID_CLIENT))
  1355.                     usClient++;
  1356.  
  1357.                 if(pTbCtlData->lState & TB_VERTICAL)
  1358.                     lOffset = pSWP[usClient].cy - HAND_SIZE;
  1359.                 else
  1360.                     lOffset = HAND_SIZE + 1;
  1361.  
  1362.  
  1363.                 for(lCount = 0; lCount < pTbCtlData->lCount; lCount++)
  1364.                 {
  1365.                     WinQueryWindowPos(pTbCtlData->hItems[lCount], &swp);
  1366.  
  1367.  
  1368.                     if(pTbCtlData->lState & TB_VERTICAL)
  1369.                     {
  1370.                         pSWP[itemCount].x  = pSWP[usClient].x;
  1371.                         pSWP[itemCount].y  = lOffset +
  1372.                                              pSWP[usClient].y - swp.cy;
  1373.                     }
  1374.                     else
  1375.                     {
  1376.                         pSWP[itemCount].x  = pSWP[usClient].x + lOffset;
  1377.                         pSWP[itemCount].y  = pSWP[usClient].y;
  1378.                     }
  1379.  
  1380.                     pSWP[itemCount].cx = swp.cx;
  1381.                     pSWP[itemCount].cy = swp.cy;
  1382.                     pSWP[itemCount].fl   = SWP_SIZE | SWP_MOVE | SWP_SHOW;
  1383.                     pSWP[itemCount].hwnd = pTbCtlData->hItems[lCount];
  1384.                     pSWP[itemCount].hwndInsertBehind = HWND_TOP;
  1385.  
  1386.                     if(pTbCtlData->lState & TB_VERTICAL)
  1387.                         lOffset -= swp.cy;
  1388.                     else
  1389.                         lOffset += swp.cx;
  1390.  
  1391.                     itemCount++;
  1392.                 }
  1393.  
  1394.                 if(pTbCtlData->lState & TB_VERTICAL)
  1395.                 {
  1396.                     pSWP[usClient].y  += pSWP[usClient].cy - HAND_SIZE;
  1397.                     pSWP[usClient].cy = HAND_SIZE;
  1398.                 }
  1399.                 else
  1400.                     pSWP[usClient].cx = HAND_SIZE;
  1401.             }
  1402.             return MRFROMSHORT(itemCount);
  1403.     }
  1404.     return pTbCtlData->pOldProc(hwnd, msg, mp1, mp2);
  1405. }
  1406.  
  1407. /* Function: TbSeparatorProc
  1408. ** Abstract: Window procedure for Toolbar Separator Window Class
  1409. */
  1410.  
  1411. MRESULT EXPENTRY TbSeparatorProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1412. {
  1413.     switch (msg)
  1414.     {
  1415.         case WM_PAINT:
  1416.             {
  1417.                 HPS hpsPaint;
  1418.                 RECTL rclPaint;
  1419.  
  1420.                 hpsPaint = WinBeginPaint(hwnd, 0, 0);
  1421.  
  1422.                 WinQueryWindowRect(hwnd, &rclPaint);
  1423.                 WinFillRect(hpsPaint, &rclPaint, CLR_PALEGRAY);
  1424.  
  1425.                 WinEndPaint(hpsPaint);
  1426.             }
  1427.             return MRFROMSHORT(FALSE);
  1428.     }
  1429.     return WinDefWindowProc(hwnd, msg, mp1, mp2);
  1430. }
  1431.  
  1432. /* Function: RecalcTbDimensions
  1433. ** Abstract: Recalculate Toolbar window dimensions
  1434. */
  1435.  
  1436. void RecalcTbDimensions(HWND hwnd, POINTL * pSize)
  1437. {
  1438.     LONG  lCount;
  1439.     POINTL ptlSize;
  1440.     POINTL ptlFSize;
  1441.     TbCtlData *pTbCtlData;
  1442.  
  1443.     pTbCtlData = (TbCtlData *)WinQueryWindowULong(hwnd, QWL_USER);
  1444.  
  1445.     ptlSize.x = (pTbCtlData->lState & TB_VERTICAL) ? 0 : HAND_SIZE;
  1446.     ptlSize.y = (pTbCtlData->lState & TB_VERTICAL) ? HAND_SIZE : 0;
  1447.  
  1448.     for(lCount = 0; lCount < pTbCtlData->lCount; lCount++)
  1449.     {
  1450.         SWP swp;
  1451.  
  1452.         WinQueryWindowPos(pTbCtlData->hItems[lCount], &swp);
  1453.  
  1454.         if(pTbCtlData->lState & TB_VERTICAL)
  1455.         {
  1456.             if(swp.cx > ptlSize.x)
  1457.                 ptlSize.x = swp.cx;
  1458.             ptlSize.y += swp.cy;
  1459.         }
  1460.         else
  1461.         {
  1462.             if(swp.cy > ptlSize.y)
  1463.                 ptlSize.y = swp.cy;
  1464.             ptlSize.x += swp.cx;
  1465.         }
  1466.     }
  1467.  
  1468.     WinSendMsg(hwnd, WM_QUERYBORDERSIZE, MPFROMP(&ptlFSize), 0);
  1469.     ptlSize.x += ptlFSize.x * 2;
  1470.     ptlSize.y += ptlFSize.y * 2;
  1471.  
  1472.     if(pSize)
  1473.         *pSize = ptlSize;
  1474.     else
  1475.         WinSetWindowPos(hwnd, 0, 0, 0, ptlSize.x, ptlSize.y, SWP_SIZE);
  1476.  
  1477. }
  1478.  
  1479. /* Function: TrackRectangle
  1480. ** Abstract: Tracks given rectangle.
  1481. **
  1482. ** If rclBounds is NULL, then track rectangle on entire desktop.
  1483. ** rclTrack is in window coorditates and will be mapped to
  1484. ** desktop.
  1485. */
  1486.  
  1487. BOOL TrackRectangle(HWND hwndBase, RECTL* rclTrack, RECTL* rclBounds)
  1488. {
  1489.     TRACKINFO track;
  1490.     APIRET rc;
  1491.     POINTL ptlSize;
  1492.  
  1493.     track.cxBorder = 1;
  1494.     track.cyBorder = 1;
  1495.     track.cxGrid   = 1;
  1496.     track.cyGrid   = 1;
  1497.     track.cxKeyboard = 8;
  1498.     track.cyKeyboard = 8;
  1499.  
  1500.     if(!rclTrack)
  1501.         return FALSE;
  1502.  
  1503.     if(rclBounds)
  1504.     {
  1505.         track.rclBoundary = *rclBounds;
  1506.     }
  1507.     else
  1508.     {
  1509.         track.rclBoundary.yTop    =
  1510.         track.rclBoundary.xRight  = 3000;
  1511.         track.rclBoundary.yBottom =
  1512.         track.rclBoundary.xLeft   = -3000;
  1513.     }
  1514.  
  1515.     track.rclTrack = *rclTrack;
  1516.  
  1517.     WinMapWindowPoints(hwndBase,
  1518.                        HWND_DESKTOP,
  1519.                        (PPOINTL)&track.rclTrack,
  1520.                        2);
  1521.  
  1522.     track.ptlMinTrackSize.x = track.rclTrack.xRight
  1523.                             - track.rclTrack.xLeft;
  1524.     track.ptlMinTrackSize.y = track.rclTrack.yTop
  1525.                             - track.rclTrack.yBottom;
  1526.     track.ptlMaxTrackSize.x = track.rclTrack.xRight
  1527.                             - track.rclTrack.xLeft;
  1528.     track.ptlMaxTrackSize.y = track.rclTrack.yTop
  1529.                             - track.rclTrack.yBottom;
  1530.  
  1531.     track.fs = TF_MOVE | TF_ALLINBOUNDARY;
  1532.  
  1533.     rc = WinTrackRect(HWND_DESKTOP, 0, &track);
  1534.  
  1535.     if(rc)
  1536.         *rclTrack = track.rclTrack;
  1537.  
  1538.     return rc;
  1539. }
  1540.  
  1541. /* Function: TbClientProc
  1542. ** Abstract: Window procedure for Toolbar Client Window Class
  1543. */
  1544.  
  1545. MRESULT EXPENTRY TbClientProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1546. {
  1547.     HWND hwndFrame = 0;
  1548.     TbCtlData* pTbCtlData;
  1549.     RECTL rclPaint;
  1550.  
  1551.     hwndFrame = WinQueryWindow(hwnd, QW_PARENT);
  1552.     pTbCtlData = (TbCtlData *)WinQueryWindowULong(hwndFrame,
  1553.                                                   QWL_USER);
  1554.     switch (msg)
  1555.     {
  1556.         case WM_ERASEBACKGROUND :
  1557.             {
  1558.                 WinFillRect((HPS)mp1, (PRECTL)mp2, SYSCLR_BUTTONMIDDLE);
  1559.             }
  1560.             return MRFROMSHORT(FALSE);
  1561.  
  1562.         case WM_PAINT:
  1563.             {
  1564.                 HPS hpsPaint;
  1565.                 POINTL ptlWork;
  1566.                 int i;
  1567.  
  1568.                 hpsPaint = WinBeginPaint(hwnd, 0, 0);
  1569.                 WinQueryWindowRect(hwnd, &rclPaint);
  1570.  
  1571.                 WinFillRect(hpsPaint, &rclPaint, CLR_PALEGRAY);
  1572.  
  1573.                 GpiSetColor(hpsPaint,CLR_WHITE);
  1574.  
  1575.                 ptlWork.x = rclPaint.xLeft   + 2;
  1576.                 ptlWork.y = rclPaint.yBottom + 2;
  1577.                 GpiMove(hpsPaint, &ptlWork);
  1578.                 ptlWork.y = rclPaint.yTop    - 2;
  1579.                 GpiLine(hpsPaint, &ptlWork);
  1580.                 ptlWork.x = rclPaint.xRight  - 2;
  1581.                 GpiLine(hpsPaint, &ptlWork);
  1582.  
  1583.                 GpiSetColor(hpsPaint,CLR_BLACK);
  1584.  
  1585.                 ptlWork.y = rclPaint.yBottom + 2;
  1586.                 GpiLine(hpsPaint, &ptlWork);
  1587.                 ptlWork.x = rclPaint.xLeft   + 2;
  1588.                 GpiLine(hpsPaint, &ptlWork);
  1589.  
  1590.                 WinEndPaint(hpsPaint);
  1591.             }
  1592.             return MRFROMSHORT(FALSE);
  1593.  
  1594.         case WM_MOUSEMOVE:
  1595.             {
  1596.                 WinSetPointer(HWND_DESKTOP,
  1597.                               WinQuerySysPointer(HWND_DESKTOP,
  1598.                                                  SPTR_MOVE,
  1599.                                                  FALSE));
  1600.             }
  1601.             return MRFROMSHORT(FALSE);
  1602.  
  1603.         case WM_BUTTON2DBLCLK: /* Switch bubble help on/off */
  1604.             if(pTbCtlData->lState & TB_BUBBLE)
  1605.             {
  1606.                 pTbCtlData->bBubble = 1 - pTbCtlData->bBubble;
  1607.             }
  1608.             break;
  1609.  
  1610.         case WM_BUTTON1DBLCLK: /* Flip horisontal/vertical */
  1611.             {
  1612.                 POINTL ptlPoint;
  1613.                 SWP swp;
  1614.  
  1615.                 /* attached toolbar can't be flipped */
  1616.  
  1617.                 if(pTbCtlData->lState & TB_ATTACHED)
  1618.                     return MRFROMSHORT(FALSE);
  1619.  
  1620.                 pTbCtlData->lState ^= TB_VERTICAL;
  1621.                 WinShowWindow(hwndFrame, FALSE);
  1622.                 RecalcTbDimensions(hwndFrame, 0);
  1623.  
  1624.                 /*
  1625.                 ** Setup new position
  1626.                 ** New positon should be aligned to mouse cursor
  1627.                 */
  1628.  
  1629.                 WinQueryPointerPos(HWND_DESKTOP,&ptlPoint);
  1630.                 WinQueryWindowPos(hwndFrame, &swp);
  1631.  
  1632.                 if(pTbCtlData->lState & TB_VERTICAL)
  1633.                     WinSetWindowPos(hwndFrame, 0,
  1634.                                     ptlPoint.x - swp.cx/2,
  1635.                                     ptlPoint.y - swp.cy + HAND_SIZE/2,
  1636.                                     0,
  1637.                                     0,
  1638.                                     SWP_MOVE);
  1639.                 else
  1640.                     WinSetWindowPos(hwndFrame, 0,
  1641.                                     ptlPoint.x - HAND_SIZE/2,
  1642.                                     ptlPoint.y - swp.cy/2,
  1643.                                     0,
  1644.                                     0,
  1645.                                     SWP_MOVE);
  1646.  
  1647.                 WinShowWindow(hwndFrame, TRUE);
  1648.             }
  1649.             return MRFROMSHORT(FALSE);
  1650.  
  1651.         case WM_BUTTON1DOWN:
  1652.             {
  1653.                 RECTL rclOwner;
  1654.                 RECTL rclFrame;
  1655.                 LONG  lState = 0;
  1656.                 LONG  lBorderX;
  1657.                 LONG  lBorderY;
  1658.                 APIRET rc;
  1659.                 POINTL ptlSize;
  1660.  
  1661.                 RecalcTbDimensions(hwndFrame, &ptlSize);
  1662.  
  1663.                 rclFrame.xLeft   = 0;
  1664.                 rclFrame.yBottom = 0;
  1665.                 rclFrame.yTop    = ptlSize.y;
  1666.                 rclFrame.xRight  = ptlSize.x;
  1667.  
  1668.                 if((pTbCtlData->lState & TB_ATTACHED) &&
  1669.                    (pTbCtlData->lState & TB_VERTICAL))
  1670.                 {
  1671.                     int iShift;
  1672.  
  1673.                     WinQueryWindowRect(hwndFrame, &rclOwner);
  1674.  
  1675.                     iShift = rclOwner.yTop - rclOwner.yBottom - ptlSize.y;
  1676.  
  1677.                     rclFrame.yBottom += iShift;
  1678.                     rclFrame.yTop    += iShift;
  1679.                 }
  1680.  
  1681.                 rc = TrackRectangle(hwndFrame, &rclFrame, 0);
  1682.  
  1683.                 if(rc != TRUE)
  1684.                     break;
  1685.  
  1686.                 /*
  1687.                 ** Check new position for the toolbar
  1688.                 ** NOTE: order of checks is important
  1689.                 */
  1690.  
  1691.                 WinQueryWindowRect(pTbCtlData->hwndParent, &rclOwner);
  1692.  
  1693.                 /* Map both points to the desktop */
  1694.  
  1695.                 WinMapWindowPoints(pTbCtlData->hwndParent,
  1696.                                    HWND_DESKTOP,
  1697.                                    (PPOINTL)&rclOwner,
  1698.                                    2);
  1699.  
  1700.                 /* Cut owner rect by titlebar and menu hight */
  1701.  
  1702.                 lBorderX = WinQuerySysValue(HWND_DESKTOP, SV_CXDLGFRAME);
  1703.                 lBorderY = WinQuerySysValue(HWND_DESKTOP, SV_CYDLGFRAME);
  1704.  
  1705.                 if(WinWindowFromID(pTbCtlData->hwndParent, FID_MENU))
  1706.                     rclOwner.yTop -= WinQuerySysValue(HWND_DESKTOP,
  1707.                                                       SV_CYMENU);
  1708.  
  1709.                 if(WinWindowFromID(pTbCtlData->hwndParent, FID_TITLEBAR))
  1710.                     rclOwner.yTop -= WinQuerySysValue(HWND_DESKTOP,
  1711.                                                       SV_CYTITLEBAR);
  1712.  
  1713.                 lState = 0;
  1714.                 if(rclFrame.xLeft >= rclOwner.xLeft - lBorderX * 2 &&
  1715.                    rclFrame.xLeft <= rclOwner.xLeft + lBorderX * 2)
  1716.                     lState = TB_ATTACHED_LT;
  1717.  
  1718.                 if(rclFrame.yTop  >= rclOwner.yTop - lBorderY * 2  &&
  1719.                    rclFrame.yTop  <= rclOwner.yTop + lBorderY * 2  )
  1720.                     lState = TB_ATTACHED_TP;
  1721.  
  1722.                 if(rclFrame.xRight >= rclOwner.xRight - lBorderX * 2 &&
  1723.                    rclFrame.xRight <= rclOwner.xRight + lBorderX * 2)
  1724.                     lState = TB_ATTACHED_RT;
  1725.  
  1726.                 if(rclFrame.yBottom >= rclOwner.yBottom - lBorderY * 2 &&
  1727.                    rclFrame.yBottom <= rclOwner.yBottom + lBorderY * 2)
  1728.                     lState = TB_ATTACHED_BT;
  1729.  
  1730.                 WinShowWindow(hwndFrame, FALSE);
  1731.  
  1732.                 if(!(pTbCtlData->lState & TB_ATTACHED) && !lState)
  1733.                 {
  1734.                     /* Toolbar is not attached and will not be attached
  1735.                        this time. Just change its position.
  1736.                      */
  1737.  
  1738.                     WinSetWindowPos(hwndFrame, 0,
  1739.                                     rclFrame.xLeft, rclFrame.yBottom,
  1740.                                     0, 0, SWP_MOVE);
  1741.                 }
  1742.  
  1743.                 if(pTbCtlData->lState & TB_ATTACHED)
  1744.                 {
  1745.                     POINTL ptlPoint;
  1746.                     SWP swp;
  1747.  
  1748.                     WinSetWindowBits(hwndFrame, QWL_STYLE, 0, FS_BORDER);
  1749.                     WinSetWindowBits(hwndFrame, QWL_STYLE, FS_DLGBORDER,
  1750.                                      FS_DLGBORDER);
  1751.                     WinSendMsg(hwndFrame,
  1752.                                WM_UPDATEFRAME,
  1753.                                MPFROMLONG(FCF_SIZEBORDER), 0);
  1754.  
  1755.                     pTbCtlData->lState &= ~TB_ATTACHED;
  1756.                     WinSetParent(hwndFrame, HWND_DESKTOP, FALSE);
  1757.                     RecalcTbDimensions(hwndFrame, 0);
  1758.  
  1759.                     WinQueryPointerPos(HWND_DESKTOP,&ptlPoint);
  1760.                     WinQueryWindowPos(hwndFrame, &swp);
  1761.  
  1762.                     if(pTbCtlData->lState & TB_VERTICAL)
  1763.                         WinSetWindowPos(hwndFrame, 0,
  1764.                                         ptlPoint.x - swp.cx/2,
  1765.                                         ptlPoint.y - swp.cy + HAND_SIZE/2,
  1766.                                         0,
  1767.                                         0,
  1768.                                         SWP_MOVE);
  1769.                     else
  1770.                         WinSetWindowPos(hwndFrame, 0,
  1771.                                         ptlPoint.x - HAND_SIZE/2,
  1772.                                         ptlPoint.y - swp.cy/2,
  1773.                                         0,
  1774.                                         0,
  1775.                                         SWP_MOVE);
  1776.                 }
  1777.  
  1778.                 if(lState)
  1779.                 {
  1780.                     pTbCtlData->lState |= lState;
  1781.  
  1782.                     WinSetWindowBits(hwndFrame, QWL_STYLE, 0, FS_DLGBORDER);
  1783.  
  1784.                     WinSetWindowBits(hwndFrame, QWL_STYLE, FS_BORDER,
  1785.                                      FS_BORDER);
  1786.  
  1787.                     WinSendMsg(hwndFrame,
  1788.                                WM_UPDATEFRAME,
  1789.                                MPFROMLONG(FCF_SIZEBORDER), 0);
  1790.  
  1791.                     WinSetFocus(HWND_DESKTOP, pTbCtlData->hwndParent);
  1792.                     WinSetParent(hwndFrame, pTbCtlData->hwndParent, FALSE);
  1793.  
  1794.                     if((lState & (TB_ATTACHED_LT | TB_ATTACHED_RT)) &&
  1795.                        !(pTbCtlData->lState & TB_VERTICAL))
  1796.                     {
  1797.                         /*
  1798.                         ** toolbar is horisontal, but we need to
  1799.                         ** attach them to vertical side
  1800.                         */
  1801.                         pTbCtlData->lState ^= TB_VERTICAL;
  1802.                     }
  1803.  
  1804.                     if((lState & (TB_ATTACHED_TP | TB_ATTACHED_BT)) &&
  1805.                        (pTbCtlData->lState & TB_VERTICAL))
  1806.                     {
  1807.                         /*
  1808.                         **toolbar is vertical, but we need to
  1809.                         **attach them to horizontal side
  1810.                         */
  1811.                         pTbCtlData->lState ^= TB_VERTICAL;
  1812.                     }
  1813.                     RecalcTbDimensions(hwndFrame, 0);
  1814.                 }
  1815.  
  1816.                 WinSendMsg(pTbCtlData->hwndParent, WM_UPDATEFRAME, 0, 0);
  1817.                 WinShowWindow(hwndFrame, TRUE);
  1818.             }
  1819.             return MRFROMSHORT(FALSE);
  1820.     }
  1821.     return WinDefWindowProc(hwnd, msg, mp1, mp2);
  1822. }
  1823.  
  1824. /* Function: ToolkitInit
  1825. ** Abstract: Registers classes needed for toolkit
  1826. */
  1827.  
  1828. void ToolkitInit(HAB aHab)
  1829. {
  1830.     hab = aHab;
  1831.     WinRegisterClass(hab,
  1832.                      CELL_CLIENT,
  1833.                      CellClientProc,
  1834.                      CS_SIZEREDRAW,
  1835.                      sizeof(ULONG));
  1836.  
  1837.     WinRegisterClass(hab,
  1838.                      TB_CLIENT,
  1839.                      TbClientProc,
  1840.                      CS_SIZEREDRAW,
  1841.                      sizeof(ULONG));
  1842.  
  1843.     WinRegisterClass(hab,
  1844.                      TB_SEPCLASS,
  1845.                      TbSeparatorProc,
  1846.                      CS_SIZEREDRAW,
  1847.                      sizeof(ULONG));
  1848. }
  1849.  
  1850. /* Function: CreateToolbar
  1851. ** Abstract: Creates toolbar for cell frame window
  1852. */
  1853.  
  1854. void CreateToolbar(HWND hwnd, TbDef* pTb)
  1855. {
  1856.     CellCtlData* pCtlData = 0;
  1857.     CellTb*      pCellTb  = 0;
  1858.     HWND hwndTb;
  1859.  
  1860.     if(!pTb || !hwnd)
  1861.         return;
  1862.  
  1863.     pCtlData = (CellCtlData *)WinQueryWindowULong(hwnd, QWL_USER);
  1864.  
  1865.     if(!pCtlData)
  1866.         return;
  1867.  
  1868.     hwndTb = CreateTb(pTb, hwnd, hwnd);
  1869.  
  1870.     if(!hwndTb)
  1871.         return;
  1872.  
  1873.     pCellTb = (CellTb*)malloc(sizeof(CellTb));
  1874.  
  1875.     if(!pCellTb)
  1876.         return;
  1877.  
  1878.     memset(pCellTb, 0, sizeof(CellTb));
  1879.  
  1880.     pCellTb->hWnd     = hwndTb;
  1881.     pCellTb->pNext    = pCtlData->pCellTb;
  1882.     pCtlData->pCellTb = pCellTb;
  1883.  
  1884.     WinSendMsg(hwnd, WM_UPDATEFRAME, 0, 0);
  1885. }
  1886.  
  1887. /* Function: CellWindowFromID
  1888. ** Abstract: Locate control window with given ID
  1889. */
  1890.  
  1891. HWND CellWindowFromID(HWND hwndCell, ULONG ulID)
  1892. {
  1893.     return (HWND)WinSendMsg(hwndCell, TKM_SEARCH_ID, MPFROMLONG(ulID), 0);
  1894. }
  1895.  
  1896. /* Function: CellWindowFromID
  1897. ** Abstract: Locate parent window for window with given ID
  1898. */
  1899.  
  1900. HWND CellParentWindowFromID(HWND hwndCell, ULONG ulID)
  1901. {
  1902.     return (HWND)WinSendMsg(hwndCell, TKM_SEARCH_PARENT, MPFROMLONG(ulID), 0);
  1903. }
  1904.  
  1905. /* Function: GenResIDStr
  1906. ** Abstract: Generate string '#nnnn' for a given ID for using with Button
  1907. **           controls
  1908. */
  1909.  
  1910. void GenResIDStr(CHAR *buff, ULONG ulID)
  1911. {
  1912.     char *str;
  1913.     int  slen = 0;
  1914.  
  1915.     *buff++ = '#';
  1916.  
  1917.     str = buff;
  1918.  
  1919.     do
  1920.     {
  1921.         *str++ = (ulID % 10) + '0';
  1922.         ulID /= 10;
  1923.         slen++;
  1924.     }
  1925.     while(ulID);
  1926.  
  1927.     *str-- = 0;
  1928.  
  1929.     for(; str > buff; str--, buff++)
  1930.     {
  1931.         *buff ^= *str;
  1932.         *str  ^= *buff;
  1933.         *buff ^= *str;
  1934.     }
  1935. }
  1936.  
  1937.